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 }
原文地址:https://www.cnblogs.com/WABoss/p/5273027.html