10.2 Morning


Problem A. distance

【题目描述】

有一个n个点m条边的无权无向联通图,满足图中不存在长度大于等于3的环,并且图中没有重边和自环。

定义两个点u,v的距离d(u,v)为这两个点之间最短路上的点数,求

                min{max d(u,v)}

【输入描述】

第一行两个数n,m,表示图的点数和边数 接下来m行,每行两个正整数描述一条边

【输出描述】

一行一个正整数,表示答案

【输入输出样例】

【input】

3 2

1 2

1 3

【output】

2

【input】

7 6

1 2

1 6

2 5

3 1

4 7

2 4

【output】

3

【数据范围】

对于30%的数据,n,m<=20

对于60%的数据,n,m<=1000

对于100%的数据,n,m<=100000


【题解】

10.2清北刷题记-LMLPHP


【代码实现】

30分代码

#include<iostream>
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn = 10050;
const int maxm = 10050;
int n, m;
int d[maxn][maxn];
int ans = 1e9;

int main()
{
    freopen("distance.in", "r", stdin);
    freopen("distance.out", "w", stdout);

    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            d[i][j] = (int)1e9;
        }
    }

    for (int i = 1; i <= m; ++i)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        d[x][y] = d[y][x] = 1;
    }

    for (int k = 1; k <= n; ++k)
    {
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                if (i == j || j == k || k == i)
                {
                    continue;
                }
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }

    /*for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            if (d[i][j] == (int)1e9)
            {
                printf("I ");
                continue;
            }
            printf("%d ", d[i][j]);
        }
        printf("\n");

    }*/

    for (int i = 1; i <= n; ++i)
    {
        int maxl = -1;
        for (int j = 1; j <= n; ++j)
        {
            if (d[i][j] >= (int)1e9)
            {
                continue;
            }
            maxl = max(maxl, d[i][j]);
        }
        ans = min(ans, maxl);
    }
    printf("%d", ans + 1);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

60分代码

#include <queue>
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAXN 100005
#define PII pair<int,int>

int n,m,cnt,ans=0x3f3f3f3f;
int head[MAXN];
int dis[MAXN],vis[MAXN];
priority_queue <PII,vector<PII>,greater<PII> >que;

struct node{
    int to,nxt;
}map[2*MAXN];

void add(int u, int v)
{
    map[++cnt] = (node){v,head[u]};
    head[u] = cnt;
}

void heap_Dij(int i)
{
    dis[i] = 1;
    que.push(make_pair(1,i));
    while(!que.empty())
    {
        int u = que.top().second;   que.pop();
        if(vis[u])  continue;
        vis[u] = 1;
        for(int k=head[u];k;k=map[k].nxt)
        {
            int v = map[k].to;
            if( dis[v] > dis[u]+1)
            {
                dis[v] = dis[u]+1;
                que.push(make_pair(dis[v],v));
            }
        }
    }
}

int main(void)
{
    freopen("distance.in","r",stdin);
    freopen("distance.out","w",stdout);
    cin >> n >> m;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        cin >> u >> v;
        add(u,v);   add(v,u);
    }
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof vis);
        memset(dis,0x3f,sizeof dis);
        heap_Dij(i);
        sort(dis+1,dis+1+n);
        ans = min(ans,dis[n]);
    }
    cout << ans;
    return 0;
}

100分代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N = (int)1e5;
typedef int arrv[N + 10];
typedef int arre[2 * N + 10];

int n, tot, j, k;
arrv g;
arre pt, nt;

void Link(int x, int y) {
    pt[++tot] = y, nt[tot] = g[x], g[x] = tot;
    pt[++tot] = x, nt[tot] = g[y], g[y] = tot;
}

void Dfs(int x, int fa, int dis) {
    if (dis > k) k = dis, j = x;
    for (int i = g[x]; i; i = nt[i])
        if (pt[i] != fa) Dfs(pt[i], x, dis + 1);
}

int main() {
    freopen("distance.in", "r", stdin);
    freopen("distance.out", "w", stdout);

    scanf("%d%d\n", &n, &k);
    for (int i = 1; i < n; ++i) scanf("%d%d\n", &j, &k), Link(j, k);

    j = k = 0;
    Dfs(1, 0, 1);
    Dfs(j, 0, 1);
    if (~k & 1) printf("%d\n", k / 2 + 1);
    else printf("%d\n", (k + 1) / 2);

    return 0;
}

Problem B. graph

【题目描述】

给定一张n个点m条边的无向图,每条边有一个权值

求一条从S到r的路径,使得这条路径上权值最大的边比上权值最小的边的比值最小

【输入描述】

第一行两个正整数n和m,表示图的边数和点数。

接下来的m行每行三个正整数x,y,z,表示连接x和y的一条权值为z的边。

最后一行两个正整数S,T。

【输出描述】

如果S到T没有通路,那么输出“ IMPOSSIBLE”(不含引号)。否则输出一个形如A/B的既约分数,表示最小的比值。

【输入输出样例】

【input】

4 2

1 2 1

3 4 2

1 4

【output】

IMPOSSIBLE

【input】

3 3

1 2 10

1 2 5

2 3 8

1 3

【output】

5/4

【input】

3 2

1 2 2

2 3 4

1 3

【output】

2

【数据范围】

对于20%的数据,n,m<=5

对于30%的数据,n<=100,m<=200,最大边权不超过100

对于100%的数据,n<=500,m<=5000,0<w<30000,x!=y,S!=T

【题解】

10.2清北刷题记-LMLPHP


【代码实现】

20分代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn = 5008;
int n, m, s, t, MX, MN, vis[maxn];
float ans = 99999.00;
typedef pair<int,int> pii;
vector <pii> G[maxn];

void dfs(int u, int mx, int mn){
    if(u == t){
        if(ans > mx/float(mn)){
            ans = mx/float(mn);
            MX = mx;
            MN = mn;
        }
        return;
    }
    for(int i=0 ; i<G[u].size() ; i++){
        int v = G[u][i].first, d = G[u][i].second;
        if(!vis[v]){
            vis[v] = 1;
            dfs(v, max(mx, d), min(mn, d));
            vis[v] = 0;
        }
    }
}

int gcd(int a, int b){
    return b ? gcd(b, a%b) : a;
}

int main(){
    freopen("graph.in","r",stdin); freopen("graph.out","w",stdout);
    scanf("%d%d", &n, &m);
    if(m >= 200){
        printf("IMPOSSIBLE\n");
        return 0;
    }
    for(int i=1 ; i<=m ; i++){
        int u, v, d;
        scanf("%d%d%d", &u, &v, &d);
        G[u].push_back(make_pair(v, d));
        G[v].push_back(make_pair(u, d));
    }
    vis[s] = 1;
    scanf("%d%d", &s, &t);
    dfs(s, -1, 0x3f3f3f3f);
    if(ans == 99999.00) printf("IMPOSSIBLE\n");
    else{
        if(MX%MN==0) printf("%d\n", MX/MN);
        else{
            int g = gcd(MX, MN);
            printf("%d/%d\n", MX/g, MN/g);
        }
    }
}

30分代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int S,T;
int N,M,to[20001],hd[20001],nxt[20001],val[20001],tot;
void puts(int x,int y,int v)
{
    ++tot;
    to[tot]=y;
    val[tot]=v;
    nxt[tot]=hd[x];
    hd[x]=tot;
}
int read()
{
    int x;char ch;
    while( ch = getchar() , ( ch < '0' || ch > '9' ) ) ;
    x=ch-'0';
    while( ch = getchar() , ( ch >='0' && ch <='9' ) )
      x=x*10+ch-'0';
    return x;
}
int dp[2][2000];
int V[10001],Q[100001],L,R;
int Ans_up=1000007,Ans_down=1;
int main()
{
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    N=read(),M=read();
    for(int i=0;i<M;i++)
    {
        int x=read(),y=read();V[i]=read();
        puts(x,y,V[i]),puts(y,x,V[i]);
    }
    S=read(),T=read();
    for(int k=0;k<M;k++)
    {
        memset(dp,0,sizeof(dp));
        L=0,Q[R=1]=S,dp[0][S]=100000007;
        while( L < R )
        {
            int x=Q[++L];
            for(int i=hd[x];i;i=nxt[i])
              if( val[i] > dp[1][to[i]] && val[i] <= V[k] )
              {
                 bool flag=0;
                 if( dp[0][to[i]] < dp[0][x] || !dp[0][to[i]] )
                    dp[0][to[i]]=min(val[i],dp[0][x]),flag=1;
                 if( dp[1][to[i]] < dp[1][x] || !dp[1][to[i]] )
                    dp[1][to[i]]=min(val[i],dp[1][x]),flag=1;
                 if( val[i] == V[k] && ( dp[1][to[i]] < dp[0][x] || !dp[1][to[i]] ) )
                    dp[1][to[i]]=min(val[i],dp[0][x]),flag=1;
                 if( flag ) Q[++R]=to[i];
              }
        }
        if( dp[1][T] && Ans_up * dp[1][T] > Ans_down * V[k] )
            Ans_up=V[k],Ans_down=dp[1][T];
    }
    if( Ans_up > 1000000 ) printf("IMPOSSIBLE");
    else
    {
        if( !( Ans_up % Ans_down ) ) printf("%d",Ans_up/Ans_down);
        else
          {
          for(int i=1;i<=Ans_up;i++)
              if( !(Ans_up%i) && !(Ans_down%i) )
                 Ans_up/=i,Ans_down/=i;
          printf("%d/%d",Ans_up,Ans_down);
          }
    }
}

100分代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int N = (int)1e4;
typedef int arr[N + 10];

int n, m, S, T;
arr ufs;
int bestnum, bestdenom;

struct edge {
    int x, y, w;
}e[N + 10];

int find(int x) { return ufs[x] == x ? x : ufs[x] = find(ufs[x]); }

int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); }

bool cmp(const edge &a, const edge &b) { return a.w < b.w; }

int main() {
    freopen("graph.in", "r", stdin);
    freopen("graph.out", "w", stdout);

    scanf("%d %d", &n, &m);
    for (int i = 1; i <= m; ++i) scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].w);
    scanf("%d %d", &S, &T);

    sort(e + 1, e + m + 1, cmp);

    bestnum = 30001, bestdenom = 1;
    for (int i = 1; i <= m; ++i) {
        for (int j = 1; j <= n; ++j) ufs[j] = j;
        int j = i;
        for ( ; j <= m; ++j) {
            int fx = find(e[j].x), fy = find(e[j].y);
            if (fx != fy) ufs[fx] = fy;
            if (find(S) == find(T)) break;
        }

        if (find(S) == find(T)) {
            if (e[j].w * bestdenom < e[i].w * bestnum)
                bestnum = e[j].w, bestdenom = e[i].w;
        }
    }

    if (bestnum == 30001) printf("IMPOSSIBLE\n");
    else {
        int g = gcd(bestnum, bestdenom);
        bestnum /= g, bestdenom /= g;
        if (bestdenom == 1) printf("%d\n", bestnum);
        else printf("%d/%d\n", bestnum, bestdenom);
    }

    return 0;
}

Problem C. sweet

【题目描述】

有一个小朋友去买糖。商店当中一共有种不同的糖果,其中每一种糖果有两种选择:大糖果和小糖果,各自只有一个,并且各自有一个价格,满足大糖果一定比小糖果贵。对于仼何一种糖果,大糖果给小朋友带来的愉悦程度是2,小糖果给小朋友带来的愉悦程度是1。由于小朋友不太喜欢口味相同的糖果混搭,所以对于一种糖果,他不会同时买大糖果和小糖果。

现在小朋友想要获得p点愉悦程度,但是想花費最少的钱,请你帮帮他。

【输入格式】

第一行两个正整数n和p 接下来n行,每行两个正整数ai和bi,表示第i种糖果小糖果和大糖果的价格。

【输出格式】

第一行输出为了获得点愉悦程度需要的最少花费。

接下来n行,第i行输岀0,1,2中的某一个数,输出0表示不买这一类糖果,输出1表示买小糖果,输出2表示买大糖果。如果有多种最优方案,输出其中一种即可。

【输入输出样例】

【input】

2 3

1 2

1 2

【output】

3

1

2

【input】

5 3

10 20

5 10

10 20

6 9

25 30

【output】

14

0

1

0

2

0

【数据范围】

对于30%的数据,n<10

对于50%的数据,n<1000,1<a<10,100<b<1000

对于10%的数据,n≤20000,ai<bi,p≤2×n,b≤2^31-1


【题解】

10.2清北刷题记-LMLPHP

10.2清北刷题记-LMLPHP


【代码实现】

30分代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iostream>

#define ri register int
#define ll long long

using namespace std;

inline void read(int &x)
{
    x = 0;
    bool f = 0;
    char ch = getchar();
    while(!isdigit(ch)) f = ch == '-', ch = getchar();
    while(isdigit(ch)) x = (x<<1) + (x<<3) + ch - 48, ch = getchar();
    if(f) x = -x;
}

const int MAXN = 1050;
int n, m, p, v[MAXN][3], dp[MAXN][3][MAXN<<1];

int min(int a, int b, int c)
{
    int ans = a;
    if(b < ans) ans = b;
    if(c < ans) ans = c;
    return ans;
}

bool vis[MAXN][3], ansvis[MAXN][3];
ll ans = 1e18;

void dfs(int x, int res, ll val)
{
//  printf("dfs %d %d %d\n", x, res, val);

    if(x > n)
    {
        if(res == 0 && val == ans)
        {
            for(ri i = 1; i <= n; i++)
            {
                if(vis[i][0]) printf("0\n");
                else if(vis[i][1]) printf("1\n");
                else printf("2\n");
            }
            exit(0);
        }
        return;
    }

    if(val > ans) return;
//  if((n-x+1)*2 < res) return;

    vis[x][1] = 1;
    if(res >= 1 && dp[x][1][p-res+1] == val+1ll*v[x][1]) dfs(x+1, res-1, val+1ll*v[x][1]);
    vis[x][1] = 0;

    vis[x][2] = 1;
    if(res >= 2 && dp[x][2][p-res+2] == val+1ll*v[x][2]) dfs(x+1, res-2, val+1ll*v[x][2]);
    vis[x][2] = 1;

    vis[x][0] = 1;
    if(dp[x][0][p-res] == val) dfs(x+1, res, val);
    vis[x][0] = 0;
}

int main()
{
    freopen("sweet.in", "r", stdin);
    freopen("sweet.out", "w", stdout);
    read(n), read(p);
    for(ri i = 1; i <= n; i++)
        read(v[i][1]), read(v[i][2]);

    memset(dp, 0x3f, sizeof(dp));
    dp[0][0][0] = 0;

    for(ri i = 1; i <= n; i++)
        for(ri j = 0; j <= i*2; j++)
        {
            dp[i][0][j] = min(dp[i-1][0][j], dp[i-1][1][j], dp[i-1][2][j]);
            if(j >= 1) dp[i][1][j] = min(dp[i-1][0][j-1], dp[i-1][1][j-1], dp[i-1][2][j-1]) + v[i][1];
            if(j >= 2) dp[i][2][j] = min(dp[i-1][0][j-2], dp[i-1][1][j-2], dp[i-1][2][j-2]) + v[i][2];
        }

    ans = min(dp[n][0][p], dp[n][1][p], dp[n][2][p]);
    printf("%lld\n", ans);

    dfs(1, p, 0);

    return 0;
}

50分代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
LL N,p,a[210000],b[210000];
LL f[1001][2002];LL pre[1001][2002];
LL read () {
    LL X=0,w=1;char ch=0;
    while(ch<'0'||ch>'9')   { if(ch=='-')   w=-1;ch=getchar(); }
    while(ch>='0'&&ch<='9') { X=(X<<1)+(X<<3)+ch-'0';ch=getchar(); }
    return X*w;
}
inline void dfs (LL N,LL p) {
    if(N==0)
        return ;
    dfs(N-1,p-pre[N][p]);
    cout << pre[N][p] << endl;
}
inline void work () {
    memset(f,0x7f,sizeof(f));
    f[0][0]=0;
    for(LL i=1;i<=N;i++)
        for(LL j=0;j<=p;j++) {
            if(f[i-1][j]<f[i][j])
                f[i][j]=f[i-1][j],pre[i][j]=0;
            if( j>=1 && f[i-1][j-1]+a[i]<f[i][j])
                f[i][j]=f[i-1][j-1]+a[i],pre[i][j]=1;
            if( j>=2 && f[i-1][j-2]+b[i]<f[i][j])
                f[i][j]=f[i-1][j-2]+b[i],pre[i][j]=2;
        }
    cout << f[N][p] << endl;
    dfs(N,p);
}
int main () {
    freopen("sweet.in","r",stdin);
    freopen("sweet.out","w",stdout);
    N=read();p=read();
    for(LL i=1;i<=N;i++)
        a[i]=read(),b[i]=read();
    work();
    return 0;
}

100分代码

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#define R "%d"
#define RL "%lld"
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define FOR(x, l, r) for (ll x = (l), end = (r); x <= end; ++x)
#define ROF(x, l, r) for (ll x = (l), end = (r); x >= end; --x)
using namespace std;

typedef int LL;
typedef long long ll;

const LL oo = (LL)2e9;
const ll INF = (ll)1e17;

const LL N = (LL)6e5;
typedef ll arr[N + 10];

struct node {
    ll x, y, z;
}a[N + 10], b[N + 10];

ll i, j, k, p, n, ma, mb, w, ans = INF, cal, mx, mxn, s, prv, prls, prmxn;
arr pr, mi, mip, sa;

bool cmp_a(const node &a, const node &b) { return a.x < b.x; }

bool cmp_b(const node &a, const node &b) { return a.x + a.y < b.x + b.y; }

LL main() {
    freopen("sweet.in", "r", stdin);
    freopen("sweet.out", "w", stdout);
    scanf(RL RL "\n", &n, &w);
    FOR (i, 1, n) {
        scanf(RL RL "\n", &j, &k);
        if (k > 2 * j) a[++ma] = (node){j, i, 1}, a[++ma] = (node){k - j, i, 2};
        else b[++mb] = (node){j, k - j, i};
    }
    sort(a + 1, a + ma + 1, cmp_a), sort(b + 1, b + mb + 1, cmp_b);

    mi[mb + 1] = oo;
    ROF (i, mb, 1)
        if (mi[i + 1] < b[i].x) mi[i] = mi[i + 1], mip[i] = mip[i + 1];
        else mi[i] = b[i].x, mip[i] = i;

    FOR (i, 1, ma) sa[i] = sa[i - 1] + a[i].x;

    FOR (ls, 0, Min(w, mb << 1)) {
        if (ls & 1) {
            p = (ls + 1) >> 1, s += b[p].x + b[p].y;
            if (b[p].y > mx) mx = b[p].y, mxn = p;
            if (w - ls > ma) continue;
            ll go = -1, ck = 0;;
            if (s - mx < s - b[p].x - b[p].y + mi[p + 1]) go = 0, ck = s - mx + sa[w - ls];
            else go = 1, ck = s - b[p].x - b[p].y + mi[p + 1] + sa[w - ls];
            if (ck < ans) {
                ans = ck;
                if (go == 0) {
                    prv = 0, prls = ls, prmxn = mxn;
                }
                else {
                    prv = 1, prls = ls;
                }
            }
        }
        else {
            p = ls >> 1;
            if (w - ls > ma) continue;
            ll ck = s + sa[w - ls];
            if (ck < ans) {
                ans = ck;
                prv = 2, prls = ls;
            }
        }
    }

    printf(RL "\n", ans);

    p = ((prls & 1) ? (prls + 1) >> 1 : prls >> 1);
    if (prv == 0) {
        FOR (i, 1, p)
            if (i != prmxn) pr[b[i].z] = 2;
            else pr[b[i].z] = 1;
        FOR (i, 1, w - prls) pr[a[i].y] = Max(pr[a[i].y], a[i].z);
    }
    else if (prv == 1) {
        FOR (i, 1, p - 1) pr[b[i].z] = 2;
        pr[b[mip[p + 1]].z] = 1;
        FOR (i, 1, w - prls) pr[a[i].y] = Max(pr[a[i].y], a[i].z);
    }
    else {
        FOR (i, 1, p) pr[b[i].z] = 2;
        FOR (i, 1, w - prls) pr[a[i].y] = Max(pr[a[i].y], a[i].z);
    }

    FOR (i, 1, n) printf(RL "\n", pr[i]);

    return 0;
}
10-06 19:54