HDU 3829 Cat VS Dog / NBUT 1305 Cat VS Dog(二分图最大匹配)
Description
The zoo have N cats and M dogs, today there are P children visiting the zoo, each child has a like-animal and a dislike-animal, if the child's like-animal is a cat, then his/hers dislike-animal must be a dog, and vice versa.
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.
Input
The input file contains multiple test cases, for each case, the first line contains three integers N <= 100, M <= 100 and P <= 500.
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)
Output
For each case, output a single integer: the maximum number of happy children.
Sample Input
1 1 2
C1 D1
D1 C1
1 2 4
C1 D1
C1 D1
C1 D2
D2 C1
Sample Output
1
3
Http
HDU:https://vjudge.net/problem/HDU-3829
NBUT:https://vjudge.net/problem/NBUT-1305
Source
二分图最大匹配
题目大意
在动物园中有n只猫和m只狗,现在来了P个小朋友,每个小朋友喜欢一只动物,不喜欢另一只动物,现在要选择移走若干只动物,若能满足喜欢的动物在而不喜欢的动物被移走,则该小朋友是开心的。现在求最多能使多少位小朋友开心。
解决思路
二分图的最大匹配问题,这里用匈牙利算法解决,算法内容可以参照我的这几篇博客:
http://www.cnblogs.com/SYCstudio/p/7138221.html
http://www.cnblogs.com/SYCstudio/p/7138230.html
那么笔者在本文就讲一讲将匈牙利算法运用在本题时,如何建图。
首先我们观察到,如果建图小朋友->动物无疑会增加算法的思考难度(反正笔者是没有想出来怎么做),那么我们就把每个小朋友i拆成两个点,开心的小朋友i和不开心的小朋友i',如果发现两个小朋友的动物需求有冲突(即i喜欢的是j不喜欢的,或i不喜欢的是j喜欢的),那么连边这两个小朋友i->j',j->i'(怎么有种回到了2-sat问题的感觉,但这和2-sat毫无关系)。然后对这个图跑一边匈牙利。
那么这时得到的最大匹配就是题目中要求的东西吗?显然不是。首先因为我们把一个点拆成了两个,这个答案要除以2;其次我们建的图是不开心的图,而题目要求的是开心的小朋友的数量,所以要用总人数P来减去除以2后的答案。这样我们就得到最终的解啦!
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxN=200;
const int maxP=1001;
const int inf=2147483647;
class Child
{
public:
int like,dislike;
};
int n,m,P;
Child C[maxP];
vector<int> E[maxP];
int Match[maxP];
bool vis[maxP];
bool Hungary(int u);
int main()
{
while (cin>>n>>m>>P)
{
memset(Match,-1,sizeof(Match));
for (int i=1;i<=P;i++)
E[i].clear();
for (int i=1;i<=P;i++)//这里把猫和狗的编号处理了一下,猫的编号为1~n,狗的编号为n+1~n+m
{
char ch;
cin>>ch;
int k=(ch=='C') ? 0 : 1;
int x;
cin>>x;
C[i].like=x+n*k;
cin>>ch;
k=(ch=='C') ? 0 : 1;
cin>>x;
C[i].dislike=x+n*k;
}
for (int i=1;i<=P;i++)//看看哪几对小朋友会冲突,建图
for (int j=i+1;j<=P;j++)
if ((C[i].like==C[j].dislike)||(C[i].dislike==C[j].like))
{
E[i].push_back(j);
E[j].push_back(i);
}
int Ans=0;
for (int i=1;i<=P;i++)//匈牙利算法
{
memset(vis,0,sizeof(vis));
if (Hungary(i))
Ans++;
}
cout<<P-Ans/2<<endl;
}
}
bool Hungary(int u)//匈牙利算法
{
for (int i=0;i<E[u].size();i++)
{
int v=E[u][i];
if (vis[v]==0)
{
vis[v]=1;
if ((Match[v]==-1)||(Hungary(Match[v])))
{
Match[v]=u;
return 1;
}
}
}
return 0;
}