zoukankan      html  css  js  c++  java
  • 隔离村庄(树形dp[01背包])

    隔离村庄

    题目描述

    有 n 个村庄,通过 n-1 条双向路连通。Jyb 同学财大气粗,想要买其中的恰好 k 个村庄。为了做一些秘密的事情,他想要通过破坏原来的路,在保证自己的 k 个村庄相互连通的情况下,把这 k 个村庄与其他村庄隔离开。请问他应该买哪 k 个村庄,最少破坏多少条路


    Solution

    dp[i][j]dp[i][j]表示以ii结点为子树, 制造大小为jj联通块所需要断的最少数目边数
    dp[i][j]=min{dp[i][pj]+dp[to][p]}dp[i][j] = min{dp[i][p-j] + dp[to][p]} 为转移方程

    初值 dp[i][1]=0dp[i][1] = 0 表示该节点为光棍时的状态,随着子树的遍历, 该值会随着改变,即转移时注意新的子树对先前dpdp值的影响, 体现在代码注释处


    Code

    #include<bits/stdc++.h>
    #define reg register
    
    const int maxn = 255;
    
    int N, K, num;
    int head[maxn], size[maxn], num_1[maxn], Tmp[maxn], dp[maxn][maxn];
    
    struct Edge{ int nxt, to; } edge[maxn << 1];
    
    void Add(int from, int to){
            edge[++ num] = (Edge){ head[from], to };
            head[from] = num;
    }
    
    void DFS(int k, int fa){
            size[k] = 1, num_1[k] = 0;
            dp[k][1] = 0;
            for(reg int i = head[k]; i; i = edge[i].nxt){
                    int to = edge[i].to;
                    if(to == fa) continue ;
                    DFS(to, k);
                    size[k] += size[to];
                    /*
                    for(reg int j = size[k]; j >= 1; j --)
                            for(reg int p = 1; p <= size[to]; p ++)
                                    dp[k][j] = std::min(dp[k][j], dp[k][j-p] + dp[to][p]);
                    */
                    for(reg int j = size[k]; j >= 1; j --){
                            dp[k][j] ++;                    //新的儿子对过去状态的影响
                            for(reg int p = 1; p < j; p ++)
                                    dp[k][j] = std::min(dp[k][j], dp[to][j - p] + dp[k][p]);
                    }
            }
    }
    
    int main(){
            freopen("isolate.in", "r", stdin);
            freopen("isolate.out", "w", stdout);
            scanf("%d%d", &N, &K);
            for(reg int i = 1; i < N; i ++){
                    int u, v;
                    scanf("%d%d", &u, &v);
                    Add(u, v), Add(v, u);
            }
            memset(dp, 0x3f, sizeof dp);
            DFS(1, 0);
            /*
            int Ans = 0x3f3f3f3f;
            for(reg int i = 1; i <= N; i ++) Ans = std::min(Ans, std::min(dp[i][N-K], dp[i][K]));
            */
            int Ans = dp[1][K];
            for(reg int i = 2; i <= N; i ++) Ans = std::min(Ans, dp[i][K] + 1);
        //    printf("%d
    ", dp[2][5]);
            printf("%d
    ", Ans);
            return 0;
    }
    
  • 相关阅读:
    P1144 最短路计数 题解 最短路应用题
    C++高精度加减乘除模板
    HDU3746 Teacher YYF 题解 KMP算法
    POJ3080 Blue Jeans 题解 KMP算法
    POJ2185 Milking Grid 题解 KMP算法
    POJ2752 Seek the Name, Seek the Fame 题解 KMP算法
    POJ2406 Power Strings 题解 KMP算法
    HDU2087 剪花布条 题解 KMP算法
    eclipse创建maven项目(详细)
    maven的作用及优势
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822679.html
Copyright © 2011-2022 走看看