题意:动物园有N只猫,M只狗,P个小孩。每个小孩都有自己喜欢的动物和讨厌的动物,如果他喜欢狗,那么就讨厌猫,如果他讨厌猫,那么他就喜欢狗。某个小孩能开心,当且仅当他喜欢的动物留在动物园和讨厌的动物不在动物园里面。现让管理员通过带走某些动物,问最多能使多少个孩子开心。
思路:正难则反的建图,我们把所有喜欢狗的孩子放在左边的点集中,所有喜欢猫的孩子放在右边的点集中.如果左边的小孩i喜欢的狗与右边的小孩j讨厌的狗是同一只的话,那么在左i与右j之间就连一条无向边.如果左边的小孩i讨厌的猫与右边的小孩j喜欢的猫是同一只的话,那么在左i与右j之间就连一条无向边.现在管理员要让尽量多的小孩高兴,明显管理员必须想办法选出尽量多的小孩出来,把他们讨厌的动物都抛弃且把他们喜欢的东西都留下才行.注意这些被选出的小孩必须满足:任意两个小孩之间不存在边.因为如果有两个小孩之间存在边,那么说明他们之间有一只动物是一个人喜欢的,另一个人讨厌的.管理员不可能同时满足他们两.
所以现在的问题是:管理员如果在新建的二分图中选出尽量多的点来,使得任意两点之间不存在边. 即最大独立集=n-最大匹配数.
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=500+10;
struct Max_Match
{
int n,m;
int g[maxn][maxn];
bool vis[maxn];
int left[maxn];
void init(int n,int m)
{
this->n=n;
this->m=m;
memset(left,-1,sizeof(left));
memset(g,0,sizeof(g));
}
bool match(int u)
{
for(int v=1;v<=m;v++)
{
if(g[u][v] && !vis[v])
{
vis[v]=true;
if(left[v]==-1 || match(left[v]))
{
left[v]=u;
return true;
}
}
}
return false;
}
int solve()
{
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(match(i)) ans++;
}
return ans;
}
}MM;
int T;
int cas = 1;
struct Node
{
int like;
int unlike;
}p1[maxn],p2[maxn];
int main()
{
int x1,x2,p;
while (scanf("%d%d%d",&x1,&x2,&p)!=EOF)
{
int num1=0;
int num2 = 0;
for (int i = 1;i<=p;i++)
{
char c1,c2;
int v1,v2;
scanf(" %c %d %c %d",&c1,&v1,&c2,&v2);
if (c1=='D')
{
p1[++num1].like=v1;
p1[num1].unlike=v2;
}
else
{
p2[++num2].like=v1;
p2[num2].unlike=v2;
}
}
MM.init(num1,num2);
for (int i = 1;i<=num1;i++)
for (int j = 1;j<=num2;j++)
{
if (p1[i].like == p2[j].unlike || p1[i].unlike==p2[j].like)
{
MM.g[i][j]=1;
}
}
printf("%d\n",p-MM.solve());
}
return 0;
}