思路:
例四是覆盖全部边,dp两个状态,例五是覆盖全部点,dp三个状态。
#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 = 1, cnt; int head[maxn]; int go[maxn << 1]; int nxt[maxn << 1]; int f[maxn]; int deep[maxn]; int val[maxn]; int dp[maxn][3]; 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(val[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][2] = val[x]; int minn = 0x3f3f3f3f, d = 0x3f3f3f3f; for(int i=head[x]; i; i=nxt[i]){ if(go[i] != f[x]){ DP(go[i]); dp[x][0] += min(dp[go[i]][1], dp[go[i]][2]); minn = min(dp[go[i]][1], dp[go[i]][2]); dp[x][1] += minn; d = min(d, dp[go[i]][2] - minn); dp[x][2] += min(min(dp[go[i]][0], dp[go[i]][1]), dp[go[i]][2]); } } dp[x][1] += d; } int main(void){ init(); DP(rt); printf("%d\n", min(dp[rt][2], dp[rt][1])); }