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 }