UVA
来源:互联网 发布:小红帽linux安装mysql 编辑:程序博客网 时间:2024/05/21 19:50
题意:
公司里有n(n<=200)个人形成一个树状结构, 要求尽量选多的人,但不能同时选择一个人和他的直属上司,文最多能选多少人,以及是否方案唯一。
分析:
dp[i]表示以i为根节点的最大独立集大小。
节点i有两种决策:选和不选,如果选i,则不能选i的所有儿子,如果不选i,则问题转化为求出i的所有儿子的dp值之和。
即:
dp[i][0]=sum{max(dp[v][0],dp[v][1]};
dp[i][1]=sum{dp[v][0]|v是i的子节点};
判断唯一性:
选i时,只要有一个子节点不唯一,则他就不唯一。
代码如下:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<iomanip>#include<cmath>#include<vector>#include<set>#include<queue>#include<map>#define INF 0x3f3f3f3fusing namespace std;const int maxn=200+10;vector<int>Map[maxn];map<string,int>p;int dp[maxn][maxn],f[maxn][maxn];int n;//遍历树void dfs(int fa){ if(Map[fa].size()==0) //如果节点是叶,则可以直接写出dp值 { dp[fa][0]=0; dp[fa][1]=1; } //搜索子节点 for(int i=0;i<Map[fa].size();i++) { int v=Map[fa][i]; dfs(v); dp[fa][1]+=dp[v][0]; //选根节点的情况 if(f[v][0]) //如果存在一个子节点不唯一,则其不唯一 f[fa][1]=1; //不选根节点的情况,则判断是否选子节点 if(dp[v][0]>dp[v][1]) //不选子节点值大 { dp[fa][0]+=dp[v][0]; if(f[v][0]) f[fa][0]=1; } else //选子节点值大 { dp[fa][0]+=dp[v][1]; if(f[v][1]||dp[v][0]==dp[v][1]) f[fa][0]=1; } }}//初始化void inite(){ //清空数组 memset(dp,0,sizeof(dp)); memset(f,0,sizeof(f)); for(int i=0;i<maxn;i++) Map[i].clear(); p.clear(); //输入,并给每个人编号 string fa_node; cin>>fa_node; int num=0; p[fa_node]=num++; for(int i=0;i<n-1;i++) { string a,b; cin>>a>>b; if(!p.count(a)) p[a]=num++; if(!p.count(b)) p[b]=num++; int m=p[a]; int n=p[b]; Map[n].push_back(m); dp[m][1]=1; //本身dp值为1 } dp[0][1]=1; //根节点dp为1}//打印输出void print_res(){ cout<<max(dp[0][0],dp[0][1])<<" "; //输出选和不选中的最大值 if(dp[0][0]==dp[0][1]) //如果相等,方案不唯一 cout<<"No"<<endl; else { if(dp[0][0]>dp[0][1]) { if(f[0][0]) cout<<"No"<<endl; else cout<<"Yes"<<endl; } else if(dp[0][1]>dp[0][0]) { if(f[0][1]) cout<<"No"<<endl; else cout<<"Yes"<<endl; } }}//主函数int main(){ while(scanf("%d",&n)!=EOF&&n) { inite(); dfs(0); print_res(); }}
阅读全文
1 0