POJ 3659 Cell Phone Network (树dp)
题目链接:http://poj.org/problem?id=3659
给你一个树形图,一个点可以覆盖他周围连接的点,让你用最少的点覆盖所有的点。
dp[i][0]表示用i点来覆盖,dp[i][1]表示用孩子节点来覆盖,dp[i][2]表示用父节点来覆盖
(1) dp[i][0] = min(dp[i.son][0], dp[i.son][1], dp[i.son][2])
(2) dp[i][1] = min(dp[i.son][0], dp[i.son][1]) //特判
(3) dp[i][2] = min(dp[i.son][0], dp[i.son][1])
注意(2)的情况,因为i需要被覆盖,所以dp[i.son][0]至少需要取到一个。
1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <ctime> 10 #include <list> 11 #include <set> 12 #include <map> 13 using namespace std; 14 typedef long long LL; 15 typedef pair <int, int> P; 16 const int N = 1e4 + 5; 17 int dp[N][3]; 18 struct Edge { 19 int next, to; 20 }edge[N << 1]; 21 int head[N], cnt; 22 23 inline void add(int u, int v) { 24 edge[cnt].next = head[u]; 25 edge[cnt].to = v; 26 head[u] = cnt++; 27 } 28 29 void dfs(int u, int p) { 30 dp[u][0] = 1, dp[u][1] = dp[u][2] = 0; 31 bool flag = false; 32 int Min = 10000; 33 for(int i = head[u]; ~i; i = edge[i].next) { 34 int v = edge[i].to; 35 if(v == p) 36 continue; 37 dfs(v, u); 38 dp[u][0] += min(dp[v][0], min(dp[v][1], dp[v][2])); 39 dp[u][2] += min(dp[v][1], dp[u][0]); 40 if(dp[v][0] <= dp[v][1]) { 41 flag = true; 42 dp[u][1] += dp[v][0]; 43 } else { 44 dp[u][1] += dp[v][1]; 45 Min = min(dp[v][0] - dp[v][1], Min); 46 } 47 } 48 if(!flag) //要是没取到dp[v][0] 49 dp[u][1] += Min; 50 } 51 52 int main() 53 { 54 int n, u, v; 55 while(~scanf("%d", &n)) { 56 memset(head, -1, sizeof(head)); 57 cnt = 0; 58 for(int i = 1; i < n; ++i) { 59 scanf("%d %d", &u, &v); 60 add(u, v); 61 add(v, u); 62 } 63 dfs(1, -1); 64 printf("%d\n", min(dp[1][0], dp[1][1])); 65 } 66 return 0; 67 }