1 条题解
-
0
#include <bits/stdc++.h> using namespace std; vector<int> G[110]; int f[110][2][2]; /* f[x][0][0]表示点x自己 不安全,没开, f[x][0][1]表示点x自己 不安全, 开, f[x][1][0]表示点x自己 安全,没开, f[x][1][1]表示点x自己 安全,开, 这里的 "安全" 代表:以x为根的子树全部安全; "不安全" 代表:以x为根的子树*只有*x点不安全。 */ void dp(int x, int fa) { f[x][0][0] = 0; f[x][0][1] = 1; f[x][1][0] = 0; f[x][1][1] = 1; int c00 = 0, c01 = 0, c10 = 0, c11 = 0; int min00 = 110, min01 = 110, min10 = 110, min11 = 110; // minXX记录孩子节点改变状态的幅度 bool bk = 0; for (int y : G[x]) if (y != fa) { dp(y, x); // f[x][0][0]表示点x自己 不安全,没开, 那么要求孩子节点有偶数个开了,即要求c00为偶数。 f[x][0][0] += min(f[y][1][0], f[y][1][1]); if (min(f[y][1][0], f[y][1][1]) == f[y][1][1]) c00++; min00 = min(min00, abs(f[y][1][0] - f[y][1][1])); // f[x][0][1]表示点x自己 不安全, 开, 那么要求孩子节点不安全,且有奇数个开了,即要求c01为奇数。 f[x][0][1] += min(f[y][0][0], f[y][0][1]); if (min(f[y][0][0], f[y][0][1]) == f[y][0][1]) c01++; min01 = min(min01, abs(f[y][0][0] - f[y][0][1])); // f[x][1][0]表示点x自己 安全,没开, 那么要求孩子节点安全,且有奇数个开了,即要求c10为奇数。 f[x][1][0] += min(f[y][1][0], f[y][1][1]); if (min(f[y][1][0], f[y][1][1]) == f[y][1][1]) c10++; min10 = min(min10, abs(f[y][1][0] - f[y][1][1])); // f[x][1][1]表示点x自己 安全,开, 那么要求孩子节点不安全,且有偶数个开了,即要求c11为偶数。 f[x][1][1] += min(f[y][0][0], f[y][0][1]); if (min(f[y][0][0], f[y][0][1]) == f[y][0][1]) c11++; min11 = min(min11, abs(f[y][0][0] - f[y][0][1])); bk = 1; } if (bk == 1) // x为非叶子节点 { if (c00 % 2 == 1) f[x][0][0] += min00; /*此时希望c00是双数,代表着孩子结点开了双数次灯,相当于没有影响到x结点。 如果c00是单数次,就会把x结点点亮,这时就要让代价最小的孩子结点改变状态。 */ if (c01 % 2 == 0) f[x][0][1] += min01; /*此时希望c01是单数,把x结点点亮,f[x][0][1]的值不用再做改变。 如果c01是双数次,相当于没有影响到x结点,这时就要让代价最小的孩子结点改变状态。 */ if (c10 % 2 == 0) f[x][1][0] += min10; /*此时希望c10是单数,把x结点点亮,f[x][1][0]的值不用再做改变。 如果c10是双数次,相当于没有影响到x结点,这时就要让代价最小的孩子结点改变状态。 */ if (c11 % 2 == 1) f[x][1][1] += min11; /*此时希望c11是双数,代表着孩子结点开了双数次灯,相当于没有影响到x结点。 如果c11是单数次,就会把x结点点亮,这时就要让代价最小的孩子结点改变状态 */ } else // x为 叶子节点 { f[x][0][0] = 0; f[x][0][1] = 110; f[x][1][0] = 110; f[x][1][1] = 1; } } int main() { int n; while (scanf("%d", &n) != EOF && n != 0) { memset(G, 0, sizeof(G)); for (int i = 1, x, y; i < n; i++) { scanf("%d%d", &x, &y); G[x].emplace_back(y); G[y].emplace_back(x); // 双向边 } int rt = 1; dp(rt, 0); printf("%d\n", min(f[rt][1][0], f[rt][1][1])); } return 0; }
- 1
信息
- ID
- 4131
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 6
- 标签
- 递交数
- 63
- 已通过
- 18
- 上传者