http://acm.hdu.edu.cn/showproblem.php?pid=1054
给定一棵树,点能看住与其相连的边,问最少需要选定多少个点看住所有的边。
定义dp[maxn][2],dp[][0]表示不选当前顶点所获得的价值,dp[][1]表示选当前顶点所获得的价值。则:
dp[u][0]=Σdp[v][1](u不选,则u的子节点v必选,否则必有边看不住,一条边只有两个点确定嘛),dp[u][1]=Σmin(dp[v][0],dp[v][1])
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<vector> 5 #include<algorithm> 6 using namespace std; 7 const int maxn=1505; 8 int dp[maxn][2],vis[maxn]; 9 vector<int> E[maxn]; 10 int n; 11 12 void dfs(int u) 13 { 14 vis[u]=1; 15 dp[u][0]=0; 16 dp[u][1]=1; 17 for(int i=0;i<E[u].size();i++){ 18 int v=E[u][i]; 19 if(vis[v]) continue; 20 dfs(v); 21 dp[u][0]+=dp[v][1]; 22 dp[u][1]+=min(dp[v][0],dp[v][1]); 23 } 24 } 25 26 int main() 27 { 28 int u,v,k; 29 while(scanf("%d",&n)==1) 30 { 31 memset(vis,0,sizeof(vis)); 32 for(int i=0;i<n;i++) E[i].clear(); 33 for(int i=0;i<n;i++){ 34 scanf(" %d:(%d)",&u,&k); 35 for(int j=0;j<k;j++){ 36 scanf(" %d",&v); 37 E[u].push_back(v); 38 E[v].push_back(u); 39 } 40 } 41 dfs(0); 42 cout<<min(dp[0][0],dp[0][1])<<endl; 43 } 44 return 0; 45 }