POJ 1947 Rebuilding Roads【树状DP】


POJ 1947 Rebuilding Roads

http://poj.org/problem?id=1947
大意:有n个点组成一个树,问至少要删除多少条边才能获得一棵有p个结点的子树?
分析:树形DP
    满足上诉条件的子树必由某个结点和它的若干子树组成,
 1.用dp[i][j]表示结点i恰好保留j个子树时至少需要删除的边数,若结点i有子树s
   a.删除子树s,dp[i][j]+1
   b.子树s保留k个结点:dp[s][k-1]+dp[i][j-k]
   综上:dp[i][j] =min(dp[i][j]+1,dp[s][k-1]+dp[i][j-k])(0<k<=j)
  
 2.默认结点1为根DFS,获取dp[i][j]值
    3.遍历所有的节点
    a.若子树根为结点1,则需删除的边为dp[1][p-1]
    b.若子树的根为节点i(i!=1),则需删除的边为dp[i][p-1]+1;
   综上:ans  = min(dp[i][p-1]+1,dp[1][p-1])(1<i<=n)

View Code
1 #include<stdio.h>
2 #include<string.h>
3 constint N =150+10;
4 struct node
5 {
6 int v;
7 node *next;
8 }edge[N*2],*index[N];
9 int ednum;
10 bool visited[N];
11
12 inline void addEdge(int a,int b)
13 {
14 node *p =&edge[ednum++];
15 p->v = b;
16 p->next = index[a];
17 index[a]=p;
18 }
19
20 int dp[N][N];//dp[i][j]表示子树i保留j个后代至少需要删除多少边
21 int n,p;//n为原树节点个数,p为所求子树的节点数
22
23 inline int min(int a,int b)
24 {
25 return a<b?a:b;
26 }
27
28 int dfs(int id)//求子树id的dp值,并返回原树中以id为根的子树包含的结点数目
29 {
30 if(visited[id]==true)return0;
31 visited[id]=true;
32
33 int sonNum =0,i,j;//sonNum统计当前节点的后代数目
34
35 for(i=1;i<=n;i++)//初始化,dp[id][i] = n表示该状态不可达
36 dp[id][i]=n;
37
38 dp[id][0]=0;//dp[id][0]表示未访问子结点前,即默认没有子节点的情况下0个孩子需要的删除0条边即可
39
40 for(node *p = index[id];p;p=p->next)
41 {
42 if(visited[p->v]==false)
43 {
44 int curSon=dfs(p->v);
45 sonNum+=curSon;
46
47 for(i=sonNum;i>0;i--)//转化为01背包求解
48 {
49 int upper = curSon;
50 if(upper>i)upper = i;
51 int temp = dp[id][i]+1;
52 for(j =1;j<=upper;j++)
53 {
54 temp = min(temp,dp[p->v][j-1]+dp[id][i-j]);
55 }
56 dp[id][i]=temp;
57 }
58 dp[id][0]++;
59 }
60 }
61
62 sonNum++;//计入本身
63 return sonNum;
64 }
65
66 int main()
67 {
68 while(scanf("%d%d",&n,&p)!=EOF)
69 {
70 int i;
71 for(i=1;i<=n;i++)
72 {
73 index[i]=NULL;
74 visited[i]=false;
75 }
76
77 int a,b;
78 ednum =0;
79 for(i=1;i<n;i++)
80 {
81 scanf("%d%d",&a,&b);
82 addEdge(a,b);
83 addEdge(b,a);
84 }
85
86 dfs(1);//计算dp值
87 int ans = dp[1][p-1];
88 for(i=2;i<=n;i++)
89 {
90 if(dp[i][p-1]+1<ans)ans = dp[i][p-1]+1;
91 }
92
93 printf("%d\n",ans);
94 }
95 return0;
96 }
原文地址:https://www.cnblogs.com/AndreMouche/p/1996102.html