• 杭电多校2020-7&&hdu 6769 In Search of Gold


    In Search of Gold

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6769

    解题思路:要求最大值最小,就采用二分的方法来做,最小就是0,最大就是所有边取最大值然后二分这个直径。

    但是我们如何求树上的直径使其最大最小,考虑dp的方法来做,dp[i][j]表示在以i为根的子树中选取m条边,经过根i的最长路径最大时,与i向相距最远的节点距离。因此我们只要使得,在dfs的过程种,这个最长路径一直小于mid就可以更新我们的dp数组,最终只要dp[1][k]小于mid则就是一个正确解。

    当然我们在dp的过程种,可能会遇到同一最远节点距选两次的情况,因此我们在求解一个子树的过程把要更新的答案占时封存起来,求解完这个子树再更新到最终的数组中。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f;
    const int maxn=4e5+10;
    struct no
    {
        int to,next;
    }edge[maxn];
    ll head[maxn],cnt,a[maxn],b[maxn],f[maxn][25],size[maxn];
    ll n,m,mid,ans;
    void add(int u,int v,ll f3,ll f4)
    {
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        a[cnt]=f3,b[cnt]=f4;
        head[u]=cnt++;
    }
    void init()
    {
        cnt=0;
        memset(head,-1, sizeof(head));
    }
    void dfs(int u,int fa)
    {
        size[u]=0;
        for(int i=0;i<=m;i++) f[u][i]=0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(v==fa) continue;
            dfs(v,u);
            int now=min(size[v]+size[u]+1,m); //now表示最多可以选取的边
            ll t[22];
            for(int j=0;j<=now;j++) t[j]=mid+1;
            for(int j=0;j<=size[u];j++)
            {
               for(int k=0;k<=size[v]&&j+k<=m;k++)
                   {if(f[u][j]+f[v][k]+a[i]<=mid) t[j+k+1]=min(t[j+k+1],max(f[u][j],f[v][k]+a[i])); //如果选a[i]并且符合条件
                   if(f[u][j]+f[v][k]+b[i]<=mid) t[j+k]=min(t[j+k],max(f[u][j],f[v][k]+b[i]));}     //如果选b[i]并且符合条件
    
            }     for(int j=0;j<=now;j++) f[u][j]=t[j];
            size[u]=now;
        }
    
    }
    int main() {
      int t;
      scanf("%d",&t);
      while(t--)
      {
         init();
        scanf("%lld%lld",&n,&m);
        ll l=1,r=0;
        for(int i=1;i<n;i++)
        {
            ll f1,f2,f3,f4;
            scanf("%lld%lld%lld%lld",&f1,&f2,&f3,&f4);
            add(f1,f2,f3,f4); 
            add(f2,f1,f3,f4);
            r+=max(f3,f4);
        }
        ll ans=r;
        while(l<=r)
        {
            mid=(l+r)/2;
            dfs(1,0);
            if(f[1][m]<=mid) ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%lld
    ",ans);
      }
    }
  • 相关阅读:
    ●sql语句-添加表和字段的说明
    ●sql-行列转换
    ●获取汉字全拼
    ●获取汉字首拼
    ●导出excel(NPOI)
    ●导出excel(office组件)
    JQuery
    CSS网页美化设计属性
    表单 框架集及CCS 20140916
    常见标签的属性及使用 20140915
  • 原文地址:https://www.cnblogs.com/tombraider-shadow/p/13385983.html
Copyright © 2020-2023  润新知