• POJ1947 Rebuilding Roads(树形DP)


    题目大概是给一棵树,问最少删几条边可以出现一个包含点数为p的连通块。

    任何一个连通块都是某棵根属于连通块的子树的上面一部分,所以容易想到用树形DP解决:

    • dp[u][k]表示以u为根的子树中,包含根的大小k的连通块最少的删边数
    • 要求答案就是min(dp[u][p],min(dp[v][p]+1)),u是整棵树的根,v是其他结点
    • 转移从若干个子树各自选择要提供几个k转移,不过指数级时间复杂度,当然又是树上背包了。。

    转移好烦,写得我好累好累。。还好1A了。。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define INF (1<<29)
     6 #define MAXN 155
     7 struct Edge{
     8     int u,v,next;
     9 }edge[MAXN];
    10 int NE,head[MAXN];
    11 void addEdge(int u,int v){
    12     edge[NE].u=u; edge[NE].v=v; edge[NE].next=head[u];
    13     head[u]=NE++;
    14 }
    15 int d[MAXN][MAXN],size[MAXN],son[MAXN];
    16 void getSize(int u){
    17     size[u]=1;
    18     son[u]=0;
    19     for(int i=head[u]; i!=-1; i=edge[i].next){
    20         int v=edge[i].v;
    21         getSize(v);
    22         size[u]+=size[v];
    23         ++son[u];
    24     }
    25 }
    26 void dp(int u){
    27     d[u][size[u]]=0;
    28     d[u][1]=0;
    29     bool first=1;
    30     for(int i=head[u]; i!=-1; i=edge[i].next){
    31         int v=edge[i].v;
    32         dp(v);
    33         ++d[u][1];
    34         if(first){
    35             for(int j=1; j<=size[v]; ++j) d[u][j+1]=d[v][j];
    36             first=0;
    37         }else{
    38             for(int j=size[u]-2; j>=1; --j){
    39                 ++d[u][j+1];
    40                 for(int k=1; k<=min(j,size[v]); ++k){
    41                     d[u][j+1]=min(d[u][j+1],d[v][k]+d[u][j+1-k]);
    42                 }
    43             }    
    44         }
    45     }
    46 }
    47 int main(){
    48     for(int i=0; i<MAXN; ++i){
    49         for(int j=0; j<MAXN; ++j) d[i][j]=INF;
    50     }
    51     memset(head,-1,sizeof(head));
    52     int n,p,a,b;
    53     scanf("%d%d",&n,&p);
    54     int deg[MAXN]={0};
    55     for(int i=1; i<n; ++i){
    56         scanf("%d%d",&a,&b);
    57         addEdge(a,b);
    58         ++deg[b];
    59     }
    60     int root;
    61     for(int i=1; i<=n; ++i){
    62         if(deg[i]==0) root=i;
    63     }
    64     getSize(root);
    65     dp(root);
    66     int res=INF;
    67     for(int i=1; i<=n; ++i){
    68         if(root==i) res=min(res,d[i][p]);
    69         else res=min(res,d[i][p]+1);
    70     }
    71     printf("%d",res);
    72     return 0;
    73 }
  • 相关阅读:
    156. Binary Tree Upside Down
    155. Min Stack
    154. Find Minimum in Rotated Sorted Array II
    153. Find Minimum in Rotated Sorted Array
    汉诺塔问题
    算法——二分搜索
    linux内核编程helloworld(中级)
    linux内核入门(1)——基本简介和编译
    linux网络编程概念(一)
    linux配置防火墙
  • 原文地址:https://www.cnblogs.com/WABoss/p/5273027.html
Copyright © 2020-2023  润新知