Poj--1947(树形DP,分组背包)

2014-12-08 16:43:29

感谢:http://www.cnblogs.com/yu-chao/archive/2011/07/18/2109730.html

思路:这题非常好,仔细思考大概思路为dp[i][j]表示以i号节点为根节点的子树,大小为j时至少要减多少条边(最优解),那么分析某个节点i,其实就是每个子节点保留一定的大小,使所有子树大小加起来等于一个值j,由于每个子树只能挑一种大小(分组背包:该组所有元素互相矛盾,只能选一个),所以就能看成分组背包问题了!

  由于背包刚开始是空的,所以分析某个节点i时,一开始它没有子节点,所以dp[i][1] = son[i](son[i]表示i的子节点总数),因为子节点全部不取要减son[i]条边。

  然后就是分组背包的转移方程了:

    for a = 1 -> son[i]

      for b = V(i节点最大可能的size) -> 2

        for c = 1 -> size of son

          dp[i][j] = min(dp[i][j],dp[i][j - k] + dp[son][k] - 1) (-1的原因是,要取该棵子树,所以要把原先减掉的其与祖先节点的边加回来)

  忠告:注意边界!

 1 /*************************************************************************
 2     > File Name: 1944.cpp
 3     > Author: Nature
 4     > Mail: 564374850@qq.com
 5     > Created Time: Sun 07 Dec 2014 08:03:04 PM CST
 6 ************************************************************************/
 7 
 8 #include <cstdio>
 9 #include <cstring>
10 #include <cstdlib>
11 #include <cmath>
12 #include <vector>
13 #include <map>
14 #include <set>
15 #include <stack>
16 #include <queue>
17 #include <iostream>
18 #include <algorithm>
19 using namespace std;
20 #define lp (p << 1)
21 #define rp (p << 1|1)
22 #define getmid(l,r) (l + (r - l) / 2)
23 #define MP(a,b) make_pair(a,b)
24 typedef long long ll;
25 const int INF = 1 << 28;
26 const int maxn = 1000;
27 
28 int N,P;
29 int first[maxn],next[maxn * 2],ver[maxn * 2],ecnt;
30 int sz[maxn],dp[maxn][maxn];
31 
32 void Init(){
33     memset(first,-1,sizeof(first));
34     ecnt = 0;
35 }
36 
37 void Add_edge(int u,int v){
38     next[++ecnt] = first[u];
39     ver[ecnt] = v;
40     first[u] = ecnt;
41 }
42 
43 int Dfs(int fa,int p){
44     sz[p] = 1;
45     int cnt = 0;
46     for(int i = first[p]; i != -1; i = next[i]){
47         int v = ver[i];
48         if(v == fa)
49             continue;
50         sz[p] += Dfs(p,v);
51         cnt++;
52     }
53     dp[p][1] = cnt;
54     for(int i = first[p]; i != -1; i = next[i]){
55         int v = ver[i];
56         if(v == fa)
57             continue;
58         for(int j = sz[p]; j > 1; --j){
59             for(int k = 1; k <= sz[v] && k < j; ++k){
60                 if(dp[p][j - k] == INF || dp[v][k] == INF) continue;
61                 dp[p][j] = min(dp[p][j],dp[p][j - k] + dp[v][k] - 1);
62             }
63         }
64     }
65     return sz[p];
66 }
67 
68 int main(){
69     int a,b;
70     Init();
71     scanf("%d%d",&N,&P);
72     for(int i = 1; i < N; ++i){
73         scanf("%d%d",&a,&b);
74         Add_edge(a,b);
75         Add_edge(b,a);
76     }
77     for(int i = 1; i <= N; ++i){
78         for(int j = 1; j <= N; ++j){
79             dp[i][j] = INF;
80         }
81     }
82     Dfs(0,1);
83     int ans = INF;
84     for(int i = 1; i <= N; ++i){
85         ans = min(ans,dp[i][P] + (i == 1 ? 0 : 1));
86     }
87     printf("%d\n",ans);
88     return 0;
89 }

 

posted @ 2014-12-08 17:00  Naturain  阅读(176)  评论(0编辑  收藏  举报