您的位置:首页 > 其它

HDU3829Cat VS Dog(二分图最大独立集)

2017-07-21 14:02 483 查看
题目描述:

动物园有N只猫,M只狗,P个小孩。每个小孩都有自己喜欢的动物和讨厌的动物,如果他喜欢狗,那么就讨厌猫,如果他讨厌猫,那么他就喜欢狗。某个小孩能开心,当且仅当他喜欢的动物留在动物园和讨厌的动物不在动物园里面。现让管理员通过带走某些动物,问最多能使多少个孩子开心。

解题思路:

题目有一个关键点,孩子喜欢猫,必然不喜欢狗,反之。 即猫和猫之间,狗和狗之间一定不存在矛盾关系,符合二分图的概念。

如何建立二分图:
若甲小孩喜欢的动物与乙小孩讨厌的动物一样,或者甲小孩讨厌的动物与乙小孩喜欢的动物一样,那甲乙之间就存在着排斥关系,则他们之间连接一条边。

建立完二分图之后,相当于求二分图的最大独立集 = 顶点数 - 最大匹配数。

因为小朋友与小朋友是没有差别的,而二分图必须要求是2个集合,现在只有一个小朋友的集合,那么我们可以用到拆点的思想,把每个小朋友拆成2个小朋友,这样在求最大匹配的时候除以2就可以了。(相当于匹配了2次~。~)。如果你拆点后,就必须建立双向边,比如1和2之间有矛盾,你不能只建立1-2矛盾边,必须还建立2-1矛盾边。

综合上述分析,只要建立双向边,求出最大匹配/2,然后用孩子的个数减去就是答案。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 505;
string like[maxn], dislike[maxn];
int head[maxn], match[maxn], child, tol;
bool vis[maxn];
struct Edge
{
int to, nxt;
}edge[maxn*maxn];
void addedge(int u, int v)
{
edge[tol].to = v;
edge[tol].nxt = head[u];
head[u] = tol++;
}
bool Match(int u)
{
for(int i = head[u]; i != -1; i = edge[i].nxt)
{
int v = edge[i].to;
if(!vis[v])
{
vis[v] = true;
if(match[v] == -1 || Match(match[v]))
{
match[v] = u;
return true;
}
}
}
return false;
}
int hungary()
{
int ret = 0;
for(int i = 0; i < child; i++)
{
memset(vis, false, sizeof(vis));
if(Match(i))
ret++;
}
return ret;
}
int main()
{
int cat, dog;
while(scanf("%d%d%d", &cat, &dog, &child) != EOF)
{
tol = 0;
memset(head, -1 ,sizeof(head));
memset(match, -1, sizeof(match));
for(int i = 0; i < child; i++)
cin >> like[i] >> dislike[i];
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)
addedge(i, j);
printf("%d\n", child - hungary() / 2);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: