zoukankan      html  css  js  c++  java
  • 牛客暑期第六场G /// 树形DP 最大流最小割定理

    题目大意:

    输入t,t个测试用例

    每个测试用例输入n

    接下来n行 输入u,v,w,树的无向边u点到v点权重为w

    求任意两点间的最大流的总和

    1.最大流最小割定理 即最大流等于最小割

    2.无向树上的任意两点都可互达 也就是说 源点S可经其他任何点流到汇点T

    设dist(x , y) 为在树上 x 到 y 的距离

    由2能知道,S的总流量就是 n∑i=1 dis( s , i )

    然后就是题解上的 S到其他各个点的距离 和 T到其他各个点的距离 中较小的即为最小割

    举个栗子

    4

    1 2 3

    1 3 4

    3 4 5

    通过树形DP

    ll dis[MAXN], son[MAXN], dp[MAXN];
    
    /// dis[ i ]为从 i 点向下的分支的长度总和
    /// son[ i ]为从 i 点向下的总点数(包括它本身)
    /// dp[ i ]为从 i 点出发去其他所有点的长度总和
    
    void dfs1(ll u,ll f) /// 求dis[],son[]
    {
        son[u]=1;
        for(int i=0;i<vec[u].size();i++) {
            ll v=vec[u][i].F, w=vec[u][i].S;
            if(v==f) continue;
            dfs1(v,u);
            son[u]+=son[v];
            dis[u]+=dis[v]+son[v]*w;
        }
    } 
    
    void dfs2(int u,int f) /// 通过dis[]进行树形DP
    {
        for(int i=0;i<vec[u].size();i++) {
            ll v=vec[u][i].F, w=vec[u][i].S;
            if(v==f) continue;
            dp[v]=dp[u]+(n-2*son[v])*w;
            dfs2(v,u);
        }
    }
    ......
    
    dfs1(1,0); dp[1]=dis[1]; dfs2(1,0);
    
    ......
    /*结果为
    dis[] 16 0 5 0
    son[] 4 1 2 1

    dp[] 16 22 16 26
    */

    可以转化为一个(姑且称之为)流量图

    括号内的是到该点的总流量

    那么 S到T的最大流 就是 两者总流量中 小的一个

    sort(dp+1,dp+1+n);
    __int128 ans=0;
    for(int i=1;i<n;i++) 
         ans += dp[i]*(n-i);

    当某个点x的总流量是所有点中的最小值时

    那么x与其他所有点的最大流就是x的总流量

    所以这里可以直接贪心 排序一下

    第 i 个点与后面比它(的总流量)小的所有点(n - i 个)直接取第 i 个

    也可以不用 __int128 ,开个数组模拟一下

        int ans[105];
        memset(ans,0,sizeof(ans));
        for(ll i=1;i<n;i++) {
            ans[0] += dp[i]*(n-i);
            int j=0;
            while(ans[j]>=1000) {
                ans[j+1] += ans[j]/1000;
                ans[j++] %= 1000;
            }
            len=max(len,j);
        }
        printf("Case #%d: %lld",o,ans[len]);
        for(int i=len-1;i>=0;i--) {
             if(ans[i]>=100) printf("%lld",ans[i]);
             else if(ans[i]>=10) printf("0%lld",ans[i]);
             else printf("00%lld",ans[i]);
        } printf("
    ");    

    完整代码

    #include <bits/stdc++.h>
    #define P pair<ll,ll>
    #define mp(i,j) make_pair(i,j)
    #define F first
    #define S second
    #define MAXN 100005
    #define ll long long
    using namespace std;
    
    vector <P> vec[MAXN];
    ll dis[MAXN], son[MAXN], dp[MAXN];
    ll n, m, ans[MAXN];
     
    void dfs1(ll u,ll f)
    {
        son[u]=1;
        for(int i=0;i<vec[u].size();i++) {
            ll v=vec[u][i].F, w=vec[u][i].S;
            if(v==f) continue;
    
            dfs1(v,u);
    
            son[u]+=son[v];
            dis[u]+=dis[v]+son[v]*w;
        }
    }
     
    void dfs2(int u,int f)
    {
        for(int i=0;i<vec[u].size();i++) {
            ll v=vec[u][i].F, w=vec[u][i].S;
            if(v==f) continue;
    
            dp[v]=dp[u]+(n-2*son[v])*w;
    
            dfs2(v,u);
        }
    }
     
    int main()
    {
        int t; scanf("%d",&t);
        for(int o=1;o<=t;o++) {
            for(int i=1;i<=n;i++) vec[i].clear();
            memset(dis,0,sizeof(dis));
            memset(son,0,sizeof(son));
            memset(dp,0,sizeof(dp));
    
            scanf("%lld",&n);
            for(int i=1;i<n;i++) {
                ll u,v,w; scanf("%lld%lld%lld",&u,&v,&w);
                vec[u].push_back(mp(v,w));
                vec[v].push_back(mp(u,w));
            }
    
            dfs1(1,0); dp[1]=dis[1]; dfs2(1,0);
            sort(dp+1,dp+1+n);
    
            int len=0;
            memset(ans,0,sizeof(ans));
            for(ll i=1;i<n;i++) {
                ans[0] += dp[i]*(n-i);
                int j=0;
                while(ans[j]>=1000) {
                    ans[j+1] += ans[j]/1000;
                    ans[j++] %= 1000;
                }
                len=max(len,j);
            }
    
            printf("Case #%d: %lld",o,ans[len]);
            for(int i=len-1;i>=0;i--) {
                if(ans[i]>=100) printf("%lld",ans[i]);
                else if(ans[i]>=10) printf("0%lld",ans[i]);
                else printf("00%lld",ans[i]);
            } printf("
    ");
        }
     
        return 0;
    }
    数组模拟
    #include <bits/stdc++.h>
    #define P pair<int,int>
    #define mp(i,j) make_pair(i,j)
    #define F first
    #define S second
    #define MAXN 100005
    using namespace std;
    vector <P> vec[MAXN];
    int son[MAXN];
    int n, m;
    __int128 dis[MAXN], dp[MAXN];
     
    void dfs1(int u,int f)
    {
        son[u]=1;
        for(int i=0;i<vec[u].size();i++) {
            int v=vec[u][i].F, w=vec[u][i].S;
            if(v==f) continue;
    
            dfs1(v,u);
    
            son[u]+=son[v];
            dis[u]+=dis[v]+son[v]*w;
        }
    }
     
    void dfs2(int u,int f)
    {
        for(int i=0;i<vec[u].size();i++) {
            int v=vec[u][i].F, w=vec[u][i].S;
    
            if(v==f) continue;
    
            dp[v]=dp[u]+(n-2*son[v])*w;
    
            dfs2(v,u);
        }
    }
     
    void print(__int128 ans)
    {
        if(ans>9) print(ans/10);
        printf("%c",'0'+ans%10);
    }
    
    int main()
    {
        int t; scanf("%d",&t);
        for(int o=1;o<=t;o++) {
    
            for(int i=1;i<=n;i++) vec[i].clear();
            memset(dis,0,sizeof(dis));
            memset(son,0,sizeof(son));
            memset(dp,0,sizeof(dp));
    
            scanf("%d",&n);
            for(int i=1;i<n;i++) {
                int u,v,w; scanf("%d%d%d",&u,&v,&w);
                vec[u].push_back(mp(v,w));
                vec[v].push_back(mp(u,w));
            }
    
            dfs1(1,0); dp[1]=dis[1]; dfs2(1,0);
    
            sort(dp+1,dp+1+n);
            __int128 ans=0;
            for(int i=1;i<n;i++) 
                ans += dp[i]*(n-i);
    
            printf("Case #%d: ",o);
            print(ans);printf("
    ");
        }
     
        return 0;
    }
    __int128
  • 相关阅读:
    JavaScript基础初始时期分支(018)
    JavaScript基础尽量少使用全局变量(001)
    linux源码安装nodejs
    js导出excel
    http 状态码
    网站导航固定头部
    gulp编译less简单demo
    mysql设置连接等待时间(wait_timeout)
    mysql视图
    网站用户行为数据挖掘
  • 原文地址:https://www.cnblogs.com/zquzjx/p/9441993.html
Copyright © 2011-2022 走看看