zoukankan      html  css  js  c++  java
  • POJ 3585 Accumulation Degree【换根DP】

    传送门http://poj.org/problem?id=3585

    题意:给定一张无根图,给定每条边的容量,随便取一点使得从这个点出发作为源点,发出的流量最大,并且输出这个最大的流量。 

    思路:最近开始做树形DP这部分的题,发现存图部分不是太会,这道题需要用到邻接表存图,不熟悉的朋友可以见我的另一篇博客:https://blog.csdn.net/weixin_43820920/article/details/98610704

    言归正传,这道题算是换根DP的裸题了,就是先随便找一个点做为根结点(u),从这个根结点(u)出发,依次找到其叶子结点

    的父亲结点的最大流量,然后在依次从下往上更新,即可得到,该根结点(u)的最大流量。但是题意并没有给我们指定结点,所

    以这就需要我们的换根了。我们可以依次枚举该根结点的孩子结点(v),将它的孩子节点(v)假设为符合题意的结点,依次更新。

    d[x]为以x为根的子树中,把x作为源点,从x发出的流量的最大值,这个用dfs扫描一次即可得出。 状态转移方程:

    d[x]=sum deg[y]==1?v(x,y):min(d[y],v(x,y))(yin son(x))

    f[x]为以x作为整棵树的根得出的答案,也只要dfs再次扫描一次。 第一次dfs是以u为根扫描的所以即是f[root]=d[root]

    状态转移方程:

    f[y]=d[y]+(deg[x]==1?v(x,y):min(f[x]-min(d[y],v(x,y)),v(x,y))),y in son(x)

    这个dfs是从上往下更新。更新结点y时,由于其父节点x已知(并且假设其父结点不为叶节点),先假设f[x]去除y这条子树时为

    w(w=f[x]-min(d[y]-v(x,y))),则此时的f[y]=d[y]+min(v(x,y),w),即是上面的状态转移方程

    代码:

    #include<iostream>
    #include<string.h>
    #include<cstdio>
    using namespace std;
    const int maxn = 200005;
    int n;
    int tot;
    struct node
    {
        int to;
        int next;
        int w;
    };
    node edges[maxn << 1];
    int deg[maxn];//结点的深度
    int head[maxn];
    //以x为根的子树中,把x作为源点,从x发出的流量的最大值
    int d[maxn];
    //以x作为整棵树的根得出的答案
    int f[maxn];
    //邻接表存图
    void add_edges(int u, int v, int w)
    {
        edges[++tot].to = v;
        edges[tot].w = w;
        edges[tot].next = head[u];
        head[u] = tot;
    }
    void init()
    {
        memset(deg, 0, sizeof(deg));
        memset(head, 0, sizeof(head));
        memset(f, 0, sizeof(f));
        memset(d, 0, sizeof(d));
        tot = 0;
    }
    void dfs1(int root, int fa)
    {
        d[root] = 0;
        for(int i = head[root]; i; i = edges[i].next)
        {
            int v = edges[i].to;
            if(v == fa)
                continue;
            else
            {
                dfs1(v, root);
                if(deg[v] == 1)
                    d[root] += edges[i].w;
                else
                    d[root] += min(d[v], edges[i].w);
            }
        }
    }
    void dfs2(int root, int fa)
    {
        for(int i = head[root]; i; i = edges[i].next)
        {
            int v = edges[i].to;
            if(v == fa)
                continue;
            else
            {
                if(deg[root] == 1)
                {
                    f[v] = d[v] + edges[i].w;
                }
                else
                {
                    f[v] = d[v] + min(f[root] - min(edges[i].w, d[v]), edges[i].w);
                }
                dfs2(v, root);
            }
        }
    }
    int main()
    {
        int t;
        scanf("%d", &t);
        while(t--)
        {
            int n;
            scanf("%d", &n);
            init();
            for(int i = 1; i < n; i++)
            {
                int x, y, v;
                scanf("%d%d%d", &x, &y, &v);
                add_edges(x, y, v);
                add_edges(y, x, v);
                deg[x]++;
                deg[y]++;
            }
    
            if(n == 0 || n == 1)
            {
                cout << 1 << endl;
                continue;
            }
            else
            {
                int root = 1;
                dfs1(root, 0);//随便取一个点做为根结点
                f[root] = d[root];
                dfs2(root, 0);
                int ans = 0;
                for(int i = 1; i <= n; i++)
                    ans = max(ans, f[i]);
                cout << ans << endl;
            }
        }
    }
  • 相关阅读:
    Hdu 1257 最少拦截系统
    Hdu 1404 Digital Deletions
    Hdu 1079 Calendar Game
    Hdu 1158 Employment Planning(DP)
    Hdu 1116 Play on Words
    Hdu 1258 Sum It Up
    Hdu 1175 连连看(DFS)
    Hdu 3635 Dragon Balls (并查集)
    Hdu 1829 A Bug's Life
    Hdu 1181 变形课
  • 原文地址:https://www.cnblogs.com/yyaoling/p/12260422.html
Copyright © 2011-2022 走看看