POJ - 3585 Accumulation Degree 树形DP + 二次扫描 + 换根法 + 最大流问题

题目描述

给定n个点, n-1条边, 边上有权值代表流量, 与网络流最大流问题相似
问以任意一点为起点, 全图的最大流量是多少
输入包括多组数据

在这里插入图片描述
样例

输入样例:
1
5
1 2 11
1 4 13
3 4 5
4 5 10
输出样例:
26

样例分析
       5个点, 4条边。当以4为起点时, 得到最大流量为26。
在这里插入图片描述

思路
       做两次扫描

  1. 任意选取一个节点当做根节点, 做一次树形DP,至下往上进行状态转移,更新D数组的值,D数组存的是D[x] 是 x的子树的最大流量
  2. 以刚才的根节点出发, 扫描所有节点, 自定往下进行更新F数组, F数组存的是 F[x] 以x为根节点的整棵树的最大总流量。

       用deg数组存节点的度, 以便判断叶子结点, 是第一次搜索时, 状态转移是如下代码所示,当y为叶子结点时, y的子树的最大流就是 d[x] + w[x][y] 这里的w[x][y]表示x 到 y 的流量,代码中用w[i]表示, 如果不是叶子结点, 流量就等于 y的子树的最大流量 和 x 到 y 的流量 取最小值。

        if(deg[y] == 1) d[x] += w[i];
        else d[x] += min(d[y], w[i]);

        在进行F数组更新时也是类似的做法,由于是自上往下更新, 所以和上面会在更新存值时有一点不同,这里也是X -->> Y 如果X是叶子结点, F[Y] = d[y] + w[x][y],不然的话, 就是F[x]的总流量减去x流向y的最大流,这就是x流向另外节点的总流量,再在这个总流量,和w[y][x]取一个最小值,就是y流向x的最大流,再加上y流向其他节点的总流量,就是以y为根节点的这棵树的最大总流量

		if(deg[x] == 1) f[y] = d[y] + w[i];
        else f[y] = d[y] + min(f[x] - min(d[y], w[i]), w[i]);

代码

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10, M = N * 2;
int e[M], ne[M], h[M], w[M], len;
int f[N], d[N], n, deg[N];
bool vis[N];
void add(int a, int b, int c){
    e[len] = b;
    w[len] = c;
    ne[len] = h[a];
    h[a] = len++;
}
void dfs_d(int x){
    d[x] = 0;
    vis[x] = true;
    for(int i = h[x]; ~i; i = ne[i]){
        int y = e[i];
        if(vis[y]) continue;
        dfs_d(y);
        if(deg[y] == 1) d[x] += w[i];
        else d[x] += min(d[y], w[i]);
    }
}
void dfs_f(int x){
    vis[x] = true;
    for(int i = h[x]; ~i; i = ne[i]){
        int y = e[i];
        if(vis[y]) continue;
        if(deg[x] == 1) f[y] = d[y] + w[i];
        else f[y] = d[y] + min(f[x] - min(d[y], w[i]), w[i]);
        dfs_f(y);
    }
}
int main(){
    int t;
    cin >> t;
    while(t--){
        cin >> n;
        len = 0;
        memset(vis, false, sizeof vis);
        memset(h, -1, sizeof h);
        memset(deg, 0, sizeof deg);
        memset(f, 0, sizeof f);
        for(int i = 1; i < n; i++){
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c), add(b, a, c);
            deg[a]++, deg[b]++;
        }
        dfs_d(1);
        f[1] = d[1];
        memset(vis, false, sizeof vis);
        dfs_f(1);
        int ans = 0;
        for(int i = 1; i <= n; i++) ans = max(ans, f[i]);
        cout << ans << endl;
        
    }
    return 0;
}

       
       
       
       

发布了68 篇原创文章 · 获赞 166 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_45432665/article/details/104223334