455. 【NOIP2017提高A组冲刺11.6】拆网线
(File IO): input:tree.in output:tree.out
Time Limits: 1000 ms Memory Limits: 65536 KB Detailed Limits
Goto ProblemSet做法:显然可以看出,俩个点间只用一条线相连的情况最优,因为这样一条线的贡献值是2,于是,树形dp,设g[x]表示 不与x节点匹配的最大的一条线的个数,f[x]表示与x节点匹配的最大的一条线的个数。
转移方程 :g[x] = Σ g[son], f[x] = max(f[x], g[x] - max(f[son], g[son]) + g[son] + 1)
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <iostream> 6 #define N 200007 7 using namespace std; 8 struct edge 9 { 10 int to, next; 11 }e[N]; 12 int t, n, m, ls[N], tot, f[N / 2], g[N / 2]; 13 14 void add(int z, int y) 15 { 16 e[++tot].to = y; 17 e[tot].next = ls[z]; 18 ls[z] = tot; 19 } 20 21 void dfs(int x, int fa) 22 { 23 for (int i = ls[x]; i; i = e[i].next) 24 { 25 if (e[i].to != fa) 26 { 27 dfs(e[i].to, x); 28 g[x] += max(f[e[i].to], g[e[i].to]); 29 } 30 } 31 32 for (int i = ls[x]; i; i = e[i].next) 33 if (e[i].to != fa) f[x] = max(f[x], g[x] - max(f[e[i].to], g[e[i].to]) + 1 + g[e[i].to]); 34 } 35 36 void work() 37 { 38 dfs(1, 0); 39 int ans = max(f[1], g[1]); 40 if (ans * 2 < m) ans += m - ans * 2; 41 else 42 { 43 if (m % 2 == 0) ans = m / 2; 44 else ans = m / 2 + 1; 45 } 46 printf("%d\n", ans); 47 } 48 49 int main() 50 { 51 freopen("tree.in", "r", stdin); 52 freopen("tree.out", "w", stdout); 53 scanf("%d", &t); 54 while (t--) 55 { 56 tot = 0; 57 memset(f, 0, sizeof(f)); 58 memset(g, 0, sizeof(g)); 59 memset(ls, 0, sizeof(ls)); 60 memset(e, 0, sizeof(e)); 61 scanf("%d%d", &n, &m); 62 for (int i = 2; i <= n; i++) 63 { 64 int x; 65 scanf("%d", &x); 66 add(x, i); 67 add(i, x); 68 } 69 work(); 70 } 71 }