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;
    }
    
  • 相关阅读:
    matlab软件-了解
    C# 自定义异常demo
    C#二进制对象copy
    asp.net 缓存依赖demo
    权限管理细粒度问题
    三层架构中的异常处理二
    如何解决复杂问题——结构化思维方式
    入职新公司如何熟悉项目
    专业工具使用与复杂大型项目设计管理
    十分钟学会 tmux
  • 原文地址:https://www.cnblogs.com/zbr162/p/11822679.html
Copyright © 2011-2022 走看看