【原题题面】传送门
【题目大意】
边连接的相邻两个节点中必有一个安排士兵,问最少需要的士兵数目。
【题解大意】
设f[x][0]表示当前节点未安排士兵的子树内的士兵的数目,f[x][1]表示当前节点安排了士兵...
f[x][0] += f[y][1];
f[x][1] += min(f[y][1],f[y][0]);
【code】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define File "" #define ll long long inline void file(){ freopen(File".in","r",stdin); freopen(File".out","w",stdout); } inline int read(){ int x = 0,f = 1; char ch = getchar(); while(ch < '0'||ch > '9'){if(ch == '-')f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x<<1) + (x<<3) + ch-'0'; ch = getchar();} return x * f; } const int mxn = 1500+10; struct edge{ int y,nxt; }e[mxn<<1]; int to[mxn],len; inline void add(int xx,int yy){ e[++len].nxt = to[xx]; to[xx] = len; e[len].y = yy; } bool v[mxn]; int f[mxn][2]; inline void dp(int x){ v[x] = 1; f[x][0] = 0,f[x][1] = 1; for(int i = to[x]; i;i = e[i].nxt){ int y = e[i].y; if(v[y]) continue; dp(y); f[x][0] += f[y][1]; f[x][1] += min(f[y][0],f[y][1]); } } int n,m,k; int main(){ // file(); while(~scanf("%d ",&n)){ memset(to,0,sizeof to); len = 1; for(int i = 1;i <= n; ++i){ scanf("%d:(%d)",&m,&k); while(k--){ int x = read(); add(m,x),add(x,m); } } int ans(0); memset(v,0,sizeof v); for(int i = 0;i < n; ++i){ if(v[i]) continue; dp(i); ans += min(f[i][0],f[i][1]); } printf("%d ",ans); } return 0; } /* 4 0:(1) 1 1:(2) 2 3 2:(0) 3:(0) 5 3:(3) 1 4 2 1:(1) 0 2:(0) 0:(0) 4:(0) */