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;
            }
        }
    }
  • 相关阅读:
    ASCII码对照表
    createPopup 超链接
    说说回车键触发表单提交的问题
    linux下配java环境的小结
    spring bind checkbox 传递值问题
    用Common validator为springMVC做验证时遇到的一个问题小记
    [转载]对android LinearLayout中layout_weight属性使用初探
    linux下tomcat启动正常,但用http://22.22.33.33:8080却访问不了,防火墙的设置问题
    Java 遍历Map时 删除元素
    ftp用户登录时不能进自己的目录,被拒绝登录的解决方法
  • 原文地址:https://www.cnblogs.com/yyaoling/p/12260422.html
Copyright © 2011-2022 走看看