zoukankan      html  css  js  c++  java
  • cf 1241 E. Paint the Tree(DP)

    题意:

    有一颗树,n个点,边有边权。

    有无限多种颜色,每个点可以同时染上k种颜色,如果一条边的两个端点 拥有至少一种相同的颜色,那么说这条边是“饱和的”。

    问:所有“饱和边”的权值和最大为多少,只需要输出最大值,不需要输出方案。

    思路:

    一开始看到这题的tag是2200,感觉肯定不会,后来发现有的人过了这题,但是却过不了D题,我就试着做做看了。结果还行。

    显然,简化题意后,就是说:

    删除一些边,使得每个点的度最多为k,求剩下的边的最大权值和。

    这种题,暴力不可取,也没有什么模板的算法可以用,所以第一感觉就是DP。

    树上的DP,一般思路就是从叶子节点回溯回去,先算子树,再转移到更大的树。

    而我们发现,这题的关键点就在于 子树的根与父节点相连 的那条边上,因为这条边取或者不取,对子树和父节点有很大影响。

    开始猜想,试着给dp[][]赋予含义,

    先不看i节点与父节点相连的那条边,dp[i][0]表示节点i取满k条边的最大权值和,dp[i][1]表示节点i取k-1条边的最大权值和,这就是给我们忽视的那条边留个位置。

    再看父节点的计算,如果我们取的这条边 可以使这棵子树的权值和变大,那么我们就取,但是最多只能取k条,所以优先取前k条增幅最大的。

    其他细节就不说了,因为我不太会说

    (思路写这么多,这么繁琐,说明这不是一篇好的题解,但是我想记录我的心路历程)

    代码:

    #include <stdio.h>
    #include <queue>
    #include <string>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    #include <map>
    #include <set>
    #include <iostream>
    using namespace std;
    typedef long long int ll;
    const int maxn = 1e6 + 10;
    const int inf = 0x3f3f3f3f;
    const ll mod = 1e9 + 7;
    const ll seed = 131;
    struct node{
        int u,v,next;
        ll val;
    }edge[maxn];
    struct node2{
        ll val;
        int id;
        bool friend operator <(node2 x,node2 y){
            return x.val < y.val;
        }
    }a[maxn];
    ll dp[maxn][2];
    int cnt,head[maxn],k;
    void add(int u,int v,int val)
    {
        edge[cnt].u = u;
        edge[cnt].v = v;
        edge[cnt].val = val;
        edge[cnt].next = head[u];
        head[u] = cnt++;
    }
    void dfs(int u,int pre)
    {
        int v,num = 0,flag = 0;
        ll temp = 0,_temp = 0;
        for(int i = head[u];i != -1;i = edge[i].next){
            v = edge[i].v;
            if(v != pre){
                flag = 1;
                dfs(v,u);
            }
        }
        for(int i = head[u];i != -1;i = edge[i].next){
            v = edge[i].v;
            if(v != pre){
                if(dp[v][1] + edge[i].val - dp[v][0] > 0){
                    a[++num].val = dp[v][1] + edge[i].val - dp[v][0];
                    a[num].id = v;
                }
                else
                    _temp += dp[v][0];
            }
        }
        if(flag == 0){
            dp[u][0] = dp[u][1] = 0;
            return ;
        }
        sort(a + 1,a + num + 1);
        for(int i = num;i >= max(num - k + 1,1);i--){
            temp += dp[a[i].id][0] + a[i].val;
        }
    
        dp[u][0] = dp[u][1] = temp + _temp;
        if(k <= num)
            dp[u][1] -= a[num - k + 1].val;
        for(int i = 1;i <= num - k;i++){
            dp[u][0] += dp[a[i].id][0];
            dp[u][1] += dp[a[i].id][0];
        }
        return ;
    }
    int main()
    {
        int t,n;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&k);
            for(int i = 0;i <= n;i++)
                head[i] = -1;
            cnt = 0;
    
            int u,v;
            ll val;
            for(int i = 1;i < n;i++){
                scanf("%d%d%lld",&u,&v,&val);
                add(u,v,val);
                add(v,u,val);
            }
            dfs(1,0);
            printf("%lld
    ",dp[1][0]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    HTTP之get post
    eclipse启动maven项目
    IDEA创建的Web项目配置Tomcat并启动Maven项目
    看django源代码有感
    给计算机系学生的建议
    自己的一点看法
    专业学习的方法
    专业思考2013.2.26
    如何通过看书来学习技术
    技术成长路线
  • 原文地址:https://www.cnblogs.com/InitRain/p/12378472.html
Copyright © 2011-2022 走看看