• HDU-6820 Tree (2020杭电多校(五) 1007)


    HDU-6820 / 2020杭电多校(五) 1007 Tree

    补题链接 参考博客

    题意:

    在一个无根树上选择一个的子图,要求子图全联通且度数大于k 的点最多只有1个。问该子图最大的权值。

    题解:

    1. 首先想到枚举这个子图中度数大于k的点,然扩展一下。这个方法复杂度太高。

    2. 可以发现叶子节点很好处理,可以从下往上处理,想到树形DP。(dp[u] [0]) 表示以u为根的子图无大于k的点的最大权值。(dp[u] [1]) 表示以u为根的子图有一个大于k的点的最大权值。我们首先默认 u 必定和其父节点 pre 连边。那么在 u 在子节点中最多连 (k - 1) 个节点。(这样做的原因是为了能够向上dp,如果u已经连了k个子节点,处理pre时无法确定与哪些子节点能连边)。 由于是最大权重,所以为了处理方便我们可以先对子节点按照(dp[v][0] + w) 从大到小排序。

    3. (dp[u][0]:​)

    [ dp[u][0]=sum_{i = 1}^{k-1}(dp[v_{i}][0]+w) ]

    1. $dp[u][1]: $ 更新(dp[u][1]) 情况较多,需要仔细思考。先设u为根的子图中度数大于k的点为p。

      • 情况1:(p=u) , 这时u是度大于k的点,那么为了权值更大肯定尽量多的连边。

        [dp[u][1]=sum_{i = 1}^{sn}(dp[v][0]+w) ]

      • 情况2:(p=v_{0}​) , 即度数大于k的点是u的一个子节点。这时u在子节点中连1个(dp[v][1]​)(k-2​)(dp[v] [0]​)。为了使权值最大选(dp[v][0]​) 时一定从最大的点开始选择。由于子节点排好序,所以我们只需要讨论一下(v_{0}​)是不是前(k-1​)个节点。设(sum=sum_{i=1}^{k-1}(dp[v_{i}][0]+w)​)

        • 1)(v_{0})是前k-1个节点,那么就需要多选择一个第k-1个节点。(其中可以用(dp[u][0])代替sum)

          [dp[u][1]=max{sum - (dp[v][0]+w) + (dp[v][1]+w)}\ dp[u][1]=max{dp[u][0]-dp[v][0]+dp[v][1]} ]

        • 2)(v_{0})不是前k-1个点,那么就只需要减去第k-1个点的值,加上(v_{0}) 的值就可以。其中mink1是第k-1个子节点的 (dp[v][0])+ w。

          [dp[u][1]=max{dp[u][0]-mink1+dp[v][1]+w} \ ]

      三种情况计算的(dp[u][1])取最大值。

    2. 前面部分dp时默认u与pre连边,现在我们要计算不u与pre不连边时的最大值。设(maxx1)(maxx2) 分别表示此时的 (dp[u][0])(dp[u][1])

      • 若子节点个数大于等于k,(maxx1=dp[u][0]+mink) 。 否则 (maxx1=dp[u][0])

      • 更新maxx2 : 和计算(dp[u][1]) 的过程一样。不过(dp[u][1]) 是讨论(v_{0}) 是前K-1个点。(maxx2) 讨论 (v_{0}) 是前k个点。

        [v属于{1...k}) maxx2 = max{maxx1-dp[v][0]+dp[v][1]} \ 其他 maxx2=max(maxx1-mink+dp[v][1]+w) ]

    3. 最后答案res = max(maxx1, maxx2)

    代码:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #include<map>
    #include<queue>
    #include<vector>
    #include<string>
    #include<fstream>
    using namespace std;
    #define rep(i, a, n) for(int i = a; i <= n; ++ i)
    #define per(i, a, n) for(int i = n; i >= a; -- i)
    typedef long long ll;
    const int N = 2e6 + 105;
    const int mod = 998244353;
    const double Pi = acos(- 1.0);
    const int INF = 0x3f3f3f3f;
    const int G = 3, Gi = 332748118;
    ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
    ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
    //
    
    int n, k;
    int head[N], cnt = 0;
    ll dp[N][2];
    ll res;
    
    struct node{
        int to, nxt; ll c;
    }edge[N];
    
    void add(int u, int v, ll w){
        edge[cnt].to = v, edge[cnt].c = w, edge[cnt].nxt = head[u], head[u] = cnt ++;
        edge[cnt].to = u, edge[cnt].c = w, edge[cnt].nxt = head[v], head[v] = cnt ++;
    }
    
    bool cmp(int a, int b){
        return dp[edge[a].to][0] + edge[a].c > dp[edge[b].to][0] + edge[b].c;
    }
    
    void dfs(int u, int pre){
        dp[u][0] = dp[u][1] = 0;
        vector<int> sol; sol.push_back(0);
        int sn = 0; //sonnum;
        for(int i = head[u]; i != -1; i = edge[i].nxt){
            int v = edge[i].to; ll w = edge[i].c;
            if(v == pre) continue;
            dfs(v, u);
            sol.push_back(i);
            sn ++;
        }
        sort(sol.begin() + 1, sol.begin() + 1 + sn, cmp);
        
        ll maxx1 = 0, maxx2 = 0;
        //dp[u][0] and maxx1
        for(int i = 1; i <= min(k - 1, sn); ++ i){
            int v = edge[sol[i]].to; ll w = edge[sol[i]].c;
            dp[u][0] += dp[v][0] + w;
        }
        if(sn >= k) maxx1 = dp[u][0] + dp[edge[sol[k]].to][0] + edge[sol[k]].c;
        else maxx1 = dp[u][0];
        res = max(res, maxx1);
        
        // dp[u][1] and maxx2
        for(int i = 1; i <= sn; ++ i){
            int v = edge[sol[i]].to; ll w = edge[sol[i]].c;
            dp[u][1] += dp[v][0] + w;
        }
        maxx2 = dp[u][1];
        
        for(int i = 1; i <= sn; ++ i){
            int v = edge[sol[i]].to; ll w = edge[sol[i]].c;
            if(i <= k - 1) dp[u][1] = max(dp[u][1], dp[u][0] - dp[v][0] + dp[v][1]);
            else if(k > 1){
                ll mink1 = dp[edge[sol[k - 1]].to][0] + edge[sol[k - 1]].c;
                dp[u][1] = max(dp[u][1], dp[u][0] - mink1 + dp[v][1] + w);
            }
        }
        
        for(int i = 1; i <= sn; ++ i){
            int v = edge[sol[i]].to; ll w = edge[sol[i]].c;
            if(i <= k) maxx2 = max(maxx2, maxx1 - dp[v][0] + dp[v][1]);
            else if(k > 0){
                ll mink = dp[edge[sol[k]].to][0] + edge[sol[k]].c;
                maxx2 = max(maxx2, maxx1 - mink + dp[v][1] + w);
            }
        }
        res = max(res, maxx2);
    }
    
    void init(){
        cnt = 0;
        res = 0;
        for(int i = 0; i <= n + 2; ++ i){
            head[i] = -1;
            dp[i][0] = dp[i][1] = 0;
        }
    }
    
    int main()
    {
        int T; scanf("%d",&T);
        while(T --){
            scanf("%d%d",&n,&k);
            init();
            for(int i = 1; i < n; ++ i){
                int x, y; ll z; scanf("%d%d%lld",&x,&y,&z);
                add(x, y, z);
            }
            if(!k){
                printf("0
    ");
                continue;
            }
            dfs(1, 0);
            printf("%lld
    ", res);
        }
        return 0;
    }
    
  • 相关阅读:
    java的nio之:java的nio系列教程之pipe
    java的nio之:java的nio系列教程之DatagramChannel
    java的nio之:java的nio系列教程之serverSocketChannel
    java的nio之:java的nio系列教程之SocketChannel
    java的nio之:java的nio系列教程之FileChannel
    java的nio之:java的nio系列教程之selector
    java的nio之:java的nio系列教程之channel的数据交换
    java的nio之:java的nio系列教程之Scatter/Gather
    java的nio之:java的nio系列教程之buffer的概念
    Mysql连接问题:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException
  • 原文地址:https://www.cnblogs.com/A-sc/p/13440370.html
Copyright © 2020-2023  润新知