牛客暑期第六场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("\n");    

完整代码

#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("\n");
    }
 
    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("\n");
    }
 
    return 0;
}
__int128

猜你喜欢

转载自www.cnblogs.com/zquzjx/p/9441993.html