POJ 1947 Rebuilding Roads
题意:给一棵含有n个节点的树,问最少切割多少条边,能够得到一棵恰好包含p个节点的子树。
解法:设d[x][i]表示以x为根的子树,切割出含有i个节点的子树最少需要切割多少条边。对于每个子节点y,可以直接将其切掉,也可以对以y为根的树进行切割,然后给以x为根的树增加节点数。这个地方其实就是一个背包,好好体会。
状态转移方程为d[x][i] = max(d[x][i]+1, d[x][i-j] + d[y][j])。
注意枚举的时候要逆序,否则要多开一维数组。
tag:树形dp, 背包
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-11-19 16:11 4 * File Name: DP-POJ-1947-2.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <vector> 10 11 using namespace std; 12 13 #define CLR(x) memset(x, 0, sizeof(x)) 14 #define PB push_back 15 const int maxint = 2147483647 / 10; 16 17 int n, p, f; 18 int d[200][200]; 19 bool vis[200]; 20 vector<int> son[200]; 21 22 void init() 23 { 24 for (int i = 1; i <= n; ++ i) 25 son[i].clear(); 26 27 CLR (vis); 28 int t1, t2; 29 for (int i = 0; i < n-1; ++ i){ 30 scanf ("%d%d", &t1, &t2); 31 vis[t2] = 1; 32 son[t1].PB (t2); 33 } 34 35 for (int i = 1; i <= n; ++ i) 36 if (!vis[i]){ 37 f = i; break; 38 } 39 } 40 41 void dfs(int x) 42 { 43 int sz = son[x].size(); 44 for (int i = 1; i <= p; ++ i) 45 d[x][i] = maxint; 46 d[x][1] = 0; 47 48 for (int t = 0; t < sz; ++ t){ 49 int v = son[x][t]; 50 dfs(v); 51 for (int i = p; i >= 1; -- i){ 52 d[x][i] += 1; 53 for (int j = 1; j < i; ++ j) 54 d[x][i] = min(d[x][i], d[x][i-j] + d[v][j]); 55 } 56 } 57 } 58 59 int main() 60 { 61 while (scanf ("%d%d", &n, &p) != EOF){ 62 init(); 63 64 dfs(f); 65 66 d[f][p] -= 1; 67 int ans = maxint; 68 for (int i = 1; i <= n; ++ i) 69 ans = min(ans, d[i][p]); 70 printf ("%d\n", ans + 1); 71 } 72 return 0; 73 }
------------------------------------------------------------------
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。
现在的你,在干什么呢?
你是不是还记得,你说你想成为岩哥那样的人。