有p个小朋友参观动物园,动物园里面有两种动物,分别为猫和狗。规定一个小朋友喜欢猫就讨厌狗,喜欢狗就讨厌猫。
现在管理员要移走0一些动物,当然,移走也是有条件的。比如一个小朋友喜欢猫3,讨厌狗4.那么移走狗4,这个小朋友就会非常开心。同样,如果移走猫3,小朋友就会很不高兴。现在问怎么样才能使开心的小朋友的人数最多。
解题思路:
刚开始想了很久,以为是一道模拟题,类似贪心或者DP什么的,可是始终找不到好的突破点,之后搜了一下,发现是二分图最大独立集。
首先想的是在猫和狗之间建边,但是仔细想想发现,如果有重复的小朋友喜欢、讨厌的都是同一种动物,那么就漏掉了很多小朋友。。这样是不行的。
然后又想了想,发现可以在小朋友之间建边,当然,是在矛盾关系的小朋友之间建边。矛盾有2种情况:我喜欢的是前面讨厌的,我讨厌的是前面喜欢的。
这样,思路就已经很清晰了。
然后就可以套用结论:二分图最大独立集=定点数-二分图最大匹配
但是在做的过程中,我又理解了一点二分图的性质:
因为小朋友与小朋友是没有差别的,而二分图必须要求是2个集合,现在只有一个小朋友的集合,那么我们可以用到拆点的思想,把每个小朋友拆成2个小朋友,这样在求最大匹配的时候除以2就可以了。(相当于匹配了2次~。~)还有一点wa了一下午的地方就是:如果你拆点后,就必须建立双向边,比如1和2之间有矛盾,你不能只建立1-2矛盾边,必须还建立2-1矛盾边。
Cat VS Dog
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 125536/65536 K (Java/Others)Total Submission(s): 1723 Accepted Submission(s): 581
Now the zoo administrator is removing some animals, if one child's like-animal is not removed and his/hers dislike-animal is removed, he/she will be happy. So the administrator wants to know which animals he should remove to make maximum number of happy children.
Next P lines, each line contains a child's like-animal and dislike-animal, C for cat and D for dog. (See sample for details)
1 1 2 C1 D1 D1 C1 1 2 4 C1 D1 C1 D1 C1 D2 D2 C1
1 3
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 510
#define N 250010
int Head[M] , Next[N] , Key[N];
int match[M];
string like[M] , dislike[M];
bool visit[M];
int num , child;
void add( int u, int v )
{
Key[num] = v;
Next[num] = Head[u];
Head[u] = num++;
}
bool find( int u )
{
int temp;
for( int i=Head[u] ; i != -1 ; i=Next[i] )
{
temp = Key[i];
if( !visit[temp] )
{
visit[temp] = true;
if( match[temp] == -1 || find(match[temp]) )
{
match[temp] = u;
return true;
}
}
}
return false;
}
int hungary( )
{
int sum = 0 ;
for( int i=0 ; i<child ; i++ )
{
memset( visit , false , sizeof(visit) );
if( find(i) )
sum++;
}
return sum;
}
int main( )
{
int cat , dog;
string likeit , dislikeit;
while( scanf("%d%d%d",&cat,&dog,&child) != EOF )
{
num = 0;
memset( Head , -1 , sizeof(Head) );
memset( match , -1 , sizeof(match) );
for( int i=0 ; i<child ; i++ )
{
cin >> likeit >> dislikeit;
like[i] = likeit;
dislike[i] = dislikeit;
}
for( int i=0 ; i<child ; i++ )
{
for( int j=0 ; j<child ; j++ )
if( like[i].compare(dislike[j]) ==0 || dislike[i].compare(like[j]) ==0 )
add( i,j );
}
printf("%d\n",child-hungary()/2);
}
return 0 ;
}