zoukankan      html  css  js  c++  java
  • 2020 Multi-University Training Contest 2 1007 In Search of Gold

    题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1007&cid=880

    题意:给你一个n个点,n-1条边的树,每条边的长度可能是a[i],也可能是b[i],有k条边的长度是取a[i],n-k-1条边的长度是取b[i]。然后要你求这棵树可能的最小直径。

    思路:要求可能的最小直径,可以想到二分数的直径看是否满足。二分看是否满足时可以用树型DP, f[i][j] 表示在 i 的子树,其中有 j 条边的的长度是取 a 数组的所有树直径 ≤ mid 的方案中,与 i 点距离最远的点到 i 的距离的最小可能值。然后转移时合并之前已经 DP过的部分和新加入的子树,如果两部分到 i 的最长距离之和超过 mid 则这颗树的直径已经超过了mid,就不需要转移了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int g[20005],v[40005],a[40005],b[40005],nxt[40005],siz[20005];
    ll f[20005][25],h[20005];
    int n,m;
    void dfs(int x,int y,ll mid)
    {
        siz[x]=f[x][0]=0;
        for(int i=g[x]; i; i=nxt[i])
        {
            int u=v[i];
            if(u==y)
                continue;
            dfs(u,x,mid);
            int A=a[i],B=b[i],pre=siz[x],cur=siz[u];
            int now=min(pre+cur+1,m);
            for(int j=0; j<=now; j++)
                h[j]=mid+1;
            for(int j=0; j<=pre; j++)
                for(int k=0; k<=cur&&j+k<=m; k++)
                {
                    if(f[x][j]+f[u][k]+A<=mid)
                        h[j+k+1]=min(h[j+k+1],max(f[x][j],f[u][k]+A));
                    if(f[x][j]+f[u][k]+B<=mid)
                        h[j+k]=min(h[j+k],max(f[x][j],f[u][k]+B));
                }
            siz[x]=now;
            for(int j=0; j<=now; j++)
                f[x][j]=h[j];
        }
    }
    int main()
    {
        int t;
        cin>>t;
        while(t--)
        {
            scanf("%d%d",&n,&m);
            ll l=0,r=0;
            for(int i=0; i<=n; i++)
                g[i]=0;
            int ed=0;
            for(int i=1; i<n; i++)
            {
                int x,y,A,B;
                scanf("%d%d%d%d",&x,&y,&A,&B);
                v[++ed]=y;
                a[ed]=A;
                b[ed]=B;
                nxt[ed]=g[x];
                g[x]=ed;
                v[++ed]=x;
                a[ed]=A;
                b[ed]=B;
                nxt[ed]=g[y];
                g[y]=ed;
                r+=max(A,B);
            }
            ll ans=0;
            while(l<=r)
            {
                ll mid=(l+r)/2;
                dfs(1,0,mid);
                if(f[1][m]<=mid)
                {
                    ans=mid;
                    r=mid-1;
                }
                else
                    l=mid+1;
            }
            printf("%lld
    ",ans);
        }
    }
  • 相关阅读:
    QR code
    复制一个带random指针的链表
    运行时const
    海量处理 bitmap及区段划分
    socket编程随记
    BLS签名
    load balancing
    Bloom Filter (2)
    #include 的花样
    拓扑排序、Dijkstra、Prim/Kruskal、全部最短路径/传递闭包
  • 原文地址:https://www.cnblogs.com/zcb123456789/p/13374491.html
Copyright © 2011-2022 走看看