题意: 有 n 只cat和 m 只dog,有 c 个小朋友,知道了每个小朋友喜欢的动物和不喜欢的动物, 现在可以将其中一些动物移走,如果剩下的动物中有某个小朋友喜欢的而没有他不喜欢的,这个小朋友就会很高兴,问最多可以让多少小朋友高兴。
思路:对于每一个小朋友,他如果喜欢狗一定讨厌猫反之亦然,所以可以把小朋友分为两部分,一部分是喜欢猫的另一部分是喜欢狗的。对于出现矛盾的两个小朋友,即我喜欢了你讨厌的小动物的这样两个小朋友,我们连一条边,那么最后的答案就是最大独立集。
由最大独立集 = 节点总数 - 匹配边数,我们只需要对于新建的图进行一次二分图最大匹配即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<string>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
//const int MAXN = 5000000 + 5;
//const int INF = 0x3f3f3f3f;
int n, m, p;
//二分匹配
const int MAXN = 505;//这个值要超过两边个数的较大者,因为有linker
int linker[MAXN];
bool used[MAXN];
int map[MAXN][MAXN];
int uN, vN;
int like[2][MAXN], dislike[2][MAXN];
bool dfs(int u)
{
for (int v = 0; v < vN; v++)
{
if(map[u][v] && !used[v])
{
used[v] = 1;
if(linker[v]==-1 || dfs(linker[v])) {
linker[v] = u;
return true;
}
}
}
return false;
}
int hungary()
{
int res = 0;
memset(linker, -1, sizeof(linker));
int u;
for (u = 0; u < uN; u++)
{
memset(used, 0, sizeof(used));
if(dfs(u)) res++;
}
return res;
}
int main()
{
//freopen("input.txt", "r", stdin);
while(cin >> n >> m >> p)
{
uN = vN = 0;
for(int i = 0; i < p; i++)
{
char tmp1, tmp2;
int num1, num2;
getchar();
scanf("%c%d", &tmp1, &num1);
getchar();
scanf("%c%d", &tmp2, &num2);
if(tmp1 == 'C')
{
like[0][uN] = num1;
dislike[0][uN] = num2;
uN++;
}
else
{
like[1][vN] = num1;
dislike[1][vN] = num2;
vN++;
}
}
for(int i = 0; i < uN; i++)
{
for(int j = 0; j < vN; j++)
{
if(like[0][i]==dislike[1][j] || dislike[0][i]==like[1][j])
map[i][j] = 1;
else map[i][j] = 0;
}
}
int ans = p - hungary();
cout << ans << endl;
}
return 0;
}