思路:
树形dp。
dp[x][0]表示以x为根的子树中不选x的最少点数,dp[x][1]表示选x的最少点数。
#include<cstdio> #include<iostream> #include<cstdlib> using namespace std; const int maxn = 3010; void qread(int &x){ x = 0; register int ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9') x = 10 * x + ch - 48, ch = getchar(); } int n, rt, cnt; int head[maxn]; int go[maxn << 1]; int nxt[maxn << 1]; int d1[maxn]; int d2[maxn]; int f[maxn]; int deep[maxn]; int sum[maxn]; int dp[maxn][2]; void dfs(int x){ for(int i = head[x]; i; i = nxt[i]) if(!deep[go[i]]){ f[go[i]] = x; deep[go[i]] = deep[x] + 1; dfs(go[i]); } } inline void init(){ qread(n); for(int i=1; i<=n; ++i){ int x, m; qread(x); qread(m); for(int j=1; j<=m; ++j){ int y; qread(y); ++cnt; go[cnt] = y; nxt[cnt] = head[x]; head[x] = cnt; ++cnt; go[cnt] = x; nxt[cnt] = head[y]; head[y] = cnt; } } deep[rt] = 1; dfs(rt); } void DP(int x){ dp[x][1] = 1; for(int i=head[x]; i; i=nxt[i]){ if(go[i] != f[x]){ DP(go[i]); dp[x][0] += dp[go[i]][1]; dp[x][1] += min(dp[go[i]][1], dp[go[i]][0]); } } } int main(void){ init(); DP(rt); printf("%d\n", min(dp[rt][0], dp[rt][1])); }