hdu 2412树形dp
Problem Description
Dear Contestant,
I'm going to have a party at my villa at Hali-Bula to celebrate my retirement from BCM. I wish I could invite all my co-workers, but imagine how an employee can enjoy a party when he finds his boss among the guests! So, I decide not to invite both an employee and his/her boss. The organizational hierarchy at BCM is such that nobody has more than one boss, and there is one and only one employee with no boss at all (the Big Boss)! Can I ask you to please write a program to determine the maximum number of guests so that no employee is invited when his/her boss is invited too? I've attached the list of employees and the organizational hierarchy of BCM.
Best,
--Brian Bennett
P.S. I would be very grateful if your program can indicate whether the list of people is uniquely determined if I choose to invite the maximum number of guests with that condition.
I'm going to have a party at my villa at Hali-Bula to celebrate my retirement from BCM. I wish I could invite all my co-workers, but imagine how an employee can enjoy a party when he finds his boss among the guests! So, I decide not to invite both an employee and his/her boss. The organizational hierarchy at BCM is such that nobody has more than one boss, and there is one and only one employee with no boss at all (the Big Boss)! Can I ask you to please write a program to determine the maximum number of guests so that no employee is invited when his/her boss is invited too? I've attached the list of employees and the organizational hierarchy of BCM.
Best,
--Brian Bennett
P.S. I would be very grateful if your program can indicate whether the list of people is uniquely determined if I choose to invite the maximum number of guests with that condition.
Input
The input consists of multiple test cases. Each test case is started with a line containing an integer n (1 ≤ n ≤ 200), the number of BCM employees. The next line contains the name of the Big Boss only. Each of the following n-1 lines contains the name of an employee together with the name of his/her boss. All names are strings of at least one and at most 100 letters and are separated by blanks. The last line of each test case contains a single 0.
Output
For each test case, write a single line containing a number indicating the maximum number of guests that can be invited according to the required condition, and a word Yes or No, depending on whether the list of guests is unique in that case.
Sample Input
6
Jason
Jack Jason
Joe Jack
Jill Jason
John Jack
Jim Jill
Sample Output
4 Yes
1 No
题目大意:一个人想邀请他的 同事和老板来参加他的party,但是没有员工想和自己的在一起啊,所有的员工有且只有一个老板,老板可能有不止一个员工,只有一个人没有老板(这个人是大老板).那么这个人该如何邀请才能使来参加party的人最多。并写出最多多少人参加party.。并且判断最多邀请人数选择是否唯一。
解题思路:
给定一棵关系树 , 从中选择一些点 , 使这些点均不存在亲子关系 , 最多能取多少个点 , 并且判断取法是否唯一 .
经典的树状 DP.
设 dp[i][0] 为在以 i 为根的子树中 , 不选择点 i 最多能够选的数目 ,dp[i][1] 为选择 i 点的最多数目 .
状态转移方程 :
当 i 为叶子节点时 :
dp[i][0]=0;
dp[i][1]=1;
当 i 为非叶子节点时 :
dp[i][0]=sum(max(dp[j][0],dp[j][1])) (j 为 i 的儿子 )
dp[i][1]=sum(dp[j][0]) (j 为 i 的儿子 )
解的唯一性的判断 :
设 u[i][x] 为 0 时表示 dp[i][x] 的解不唯一 , 为 1 则表示唯一 .
当 x 为 0 时 , 若存在 j 是 i 的儿子 , 使得 dp[j][0]>dp[j][1] 且 u[j][0]=0, 或 dp[j][0]<dp[j][1] 且 u[j][1]=0 或 dp[j][0]=dp[j][1], 则 u[i][0]=0;
当 x 为 1 时 , 若存在 j 是 i 的儿子 , 使得 u[j][0]=1, 则 u[i][0]=0;
#include<iostream> #include<cstdio> #include<map> #include<vector> #include<string> #include<cstring> using namespace std; map<string,int> mp; vector<int> v[205]; int dp[205][2]; int dup[205][2]; void clean(int n){ mp.clear(); for(int i=0;i<=n;i++){ v[i].clear(); } memset(dp,0,sizeof dp); } void dfs(int x){ int r=v[x].size();//编号为x的树,其子树的个数 dup[x][0]=1; dup[x][1]=1; if(r==0){//若子树个数为0,说明x为叶子 dp[x][0]=0; dp[x][1]=1; return ; } for(int i=0;i<r;i++){//求x的每一个子树的最优解,并将其相加得到x的最优解 int next=v[x][i];//x的第i个子树 dfs(next);//对x的第i个子树递归求最优解 //编号为x的树最优解为选择x时的最优解和不选择x时的最优解 dp[x][0]+=max(dp[next][0],dp[next][1]);//不选择树x时,其最优解,为每一个子树的最优解的和,x每一个子树的最优解为选择其本身时的最优解,和不选择其本身时的最优解中较大的一个 dp[x][1]+=dp[next][0];//当选择树x时,最优解为其所有子树最优解的和,x每一个子树最优解只能是不选择其本身的最优解。 //dup[x][0]=0表示以x为根且不选择x结点的树最优解不唯一,有三种情况 if(dp[next][0]>dp[next][1]&&dup[next][0]==0){ dup[x][0]=0; }else if(dp[next][1]>dp[next][0]&&dup[next][1]==0){ dup[x][0]=0; }else if(dp[next][0]==dp[next][1]){ dup[x][0]=0; } //dup[x][1]==0表示以x为根的树选择根节点x的时候的最优解 if(dup[next][0]==0){ dup[x][1]=0; } } dp[x][1]+=1;//当选择根结点时,其最优解要将根节点加上; } int main(){ int n; while(cin>>n){ int count=0; if(n==0){ break; } clean(n); string str1,str2; cin>>str1; mp[str1]=count++; //map用来存储每个节点及其对应的序号;vector<int> v[205]用来存储str1,与str2对应的关系其中,str2表示父节点,str1表示子节点 for(int i=1;i<n;i++){ cin>>str1>>str2; if(mp.find(str1)==mp.end()){//若map中不存在str1, mp[str1]=count++; } if(mp.find(str2)==mp.end()){//若map中不存在str2 mp[str2]=count++; } v[mp[str2]].push_back(mp[str1]); } dfs(0); bool istrue=true; int ans=max(dp[0][0],dp[0][1]); if(dp[0][0]>dp[0][1]&&dup[0][0]==0){ istrue=false; }else if(dp[0][0]<dp[0][1]&&dup[0][1]==0){ istrue=false; }else if(dp[0][0]==dp[0][1]){ istrue=false; } if (istrue) printf("%d %s\n",ans,"Yes"); else printf("%d %s\n",ans,"No"); } }