Party at Hali-Bula 树形dp之树的最大独立集和判断唯一性 (紫薯系列)
题意:就是给一个树,问你最大的独立集,取答案时是否唯一。 思路:参考紫书的想法。对于最大独立集来说,每个结点都有选和不选。所以有两种情况: 1.选了这个节点,那么它对应的子节点都不能选。转移方程是 d[1][u]=sum(d[0][v]) v是u的所有儿子节点。那么唯一性来说,当且仅当你所有的结点都是唯一的,那么该节点才是唯一的。 有f[1][u]=(f[1][u]&&f[0][v]) . 2.不选这个节点,那么对于它的每个子节点,我们可选可不选。即d[0][u]=max(d[1][v],d[1][v]).对于唯一性,当且仅当你选的结点都是唯一的(无论是选或者不选),那么这次选择才是唯一的。如果有某个子节点的d[1][v]=d[0][v],那么该节点也是一定不会是唯一的。 有了思路,代码就很好打出来了。注意边界,为了方便操作,借鉴超级源点的思路,在根上在加多一个点(标记为0,根是1)。然后从0出发,第一次选择当然就是选不选根,然后递归地解决问题。当然树形问题大都用递归解决
代码:
#include<bits/stdc++.h> using namespace std; const int maxn =205; int n,cnt; unordered_map<string,int> mp; vector<int> v[maxn]; int id(string s){ if(!mp.count(s)){ return mp[s]= ++cnt; } else return mp[s]; } int f[2][maxn];int d[2][maxn]; int dfs(int k,int u){ if(d[k][u]!=-1) return d[k][u]; if(v[u].size()==0){ f[k][u]=true; if(k==0) d[k][u]=0; else d[k][u]=1; } else if(k==1){ int tot=1; int m=v[u].size();bool flag_1=true; for(int i=0;i<m;i++){ tot+=dfs(0,v[u][i]); flag_1=flag_1&&f[0][v[u][i]]; } d[k][u]=tot;f[k][u]=flag_1; } else { int tot=0;bool flag=true; int m=v[u].size(); for(int i=0;i<m;i++){ int val_1=dfs(1,v[u][i]);int val_2=dfs(0,v[u][i]); int val_3=max(val_1,val_2); if(val_1==val_2) flag=false,tot+=val_1; else if(val_3==val_1){ tot+=val_3;flag=flag&&f[1][v[u][i]]; } else { tot+=val_3;flag=flag&&f[0][v[u][i]]; } } d[k][u]=tot;f[k][u]=flag; } return d[k][u]; } int main(){ while(scanf("%d",&n)==1&&n){ string s1,s2;cin>>s1;cnt=0; mp.clear(); for(int i=0;i<=n;i++) v[i].clear(); id(s1); for(int i=0;i<n-1;i++){ cin>>s1>>s2; v[id(s2)].push_back(id(s1)); } for(int i=0;i<=n;i++){ f[0][i]=f[1][i]=false; d[0][i]=d[1][i]=-1; } v[0].push_back(1); dfs(0,0); cout<<d[0][0]<<' '; if(f[0][0]) cout<<"Yes"; else cout<<"No"; cout<<endl; } return 0;}