树的最大独立集:对于一颗n个结点的无根树,选出尽量多的结点,使得任何两个结点都不相邻。
题解:dp[ i ][ 0 ~ 1 ]表示以 i 为根结点的子树的最大独立集,0表示不选 i ,1表示选 i 。记 i 的儿子为son。
选 i 的话,其儿子可选可不选,即dp[ i ][ 1 ]+=min(dp[ son ][ 0 ],dp[ son ][ 1 ]);不选 i 的话,就必须选 i 的儿子,即dp[ i ][ 0 ]+=dp[ son ][ 1 ]。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 #include<vector> 6 #define mem(array) memset(array,0,sizeof(array)) 7 using namespace std; 8 9 int n,dp[1600][2]; 10 bool vis[1600]; 11 vector<int> G[1600]; 12 13 void Read(){ 14 for(int i=0;i<n;i++) G[i].clear(); 15 for(int i=0;i<n;i++){ 16 int a,b,c; 17 scanf("%d:(%d)",&a,&b); 18 for(int j=0;j<b;j++){ 19 scanf("%d",&c); 20 G[a].push_back(c); 21 G[c].push_back(a); 22 } 23 } 24 } 25 26 void DFS(int root){ 27 dp[root][1]=1; 28 dp[root][0]=0; 29 vis[root]=true; 30 31 for(int i=0;i<G[root].size();i++){ 32 int sons=G[root][i]; 33 if(vis[sons]) continue; 34 35 DFS(sons); 36 dp[root][0]+=dp[sons][1]; 37 dp[root][1]+=min(dp[sons][1],dp[sons][0]); 38 } 39 } 40 41 int main() 42 { while(~scanf("%d",&n)){ 43 Read(); 44 mem(vis);mem(dp); 45 DFS(0); 46 cout<<min(dp[0][1],dp[0][0])<<endl; 47 } 48 return 0; 49 }