题目链接:LibreOJ 10156 战略游戏
题目大意:
题解:
很明显是树形(dp)题。
设(dp[i][0/1])表示第(i)个点不放/放士兵所需的最少士兵数。
如果当前节点不放士兵,子节点要放士兵;如果当前节点放士兵,子节点可放可不放。
状态转移方程为:
[left{egin{aligned}
dp[u][0] &= sum dp[v][1] \
dp[u][1] &= 1+sum min{dp[v][0], dp[v][1]}
end{aligned}
ight.
]
#include <cstring>
#include <iostream>
using namespace std;
#define N 1510
int n, head[N], cnt, dp[N][2];
struct Edge {
int v, next;
} edge[N << 1];
void addEdge(int u, int v) {
edge[++cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
void dfs(int u, int pre) {
dp[u][0] = 0;
dp[u][1] = 1;
for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v;
if (v == pre) {
continue;
}
dfs(v, u);
dp[u][0] += dp[v][1];
dp[u][1] += min(dp[v][0], dp[v][1]);
}
}
int main() {
memset(head, -1, sizeof(head));
cin >> n;
for (int i = 1, u, k; i <= n; ++i) {
cin >> u >> k;
for (int j = 1, v; j <= k; ++j) {
cin >> v;
addEdge(u, v);
addEdge(v, u);
}
}
dfs(0, -1);
cout << min(dp[0][1], dp[0][0]);
return 0;
}