您的位置:首页 > 其它

kuangbin专题十 HDU3829 二分图+最大独立集

2018-01-12 18:21 344 查看
题意:

动物园有N只猫,M只狗,P个小孩。每个小孩都有自己喜欢的动物和讨厌的动物,如果他喜欢狗,那么就讨厌猫,

如果他讨厌猫,那么他就喜欢狗。当他喜欢的动物留在动物园和讨厌的动物不在动物园里面,小朋友就开心。

现让管理员通过带走某些动物,问最多能使多少个孩子开心。

题解:

最大独立集=顶点数-最大匹配数(最小顶点覆盖)。一开始想着猫和狗联系上,但是发现不对劲,于是想了很久还是没思绪,别人说可以连接人,然后我想了想对哦,可以连接人,怎么连接呢?只要找到小孩A喜欢的动物和小孩B不喜欢的动物相同的时候说明这两个孩子有矛盾,将两个小孩连起来。然后求出最大独立集(这个集合里的小孩没有矛盾)就好了。但是有一个点让我苦思不得其解,为什么要建立双向边,有的时候又不需要建立双向边,一直在想,找了一下以前的题,于是我大胆的总结了一下,是不是求最小点覆盖的时候就是双向的,求最小路径覆盖的时候就是单向的呢?因为所谓最小路径覆盖,是指在一个有向图中,找出最少的几条路径,用它们来覆盖全图,请问我的观点对吗?希望有大佬给出指点,我实在是不懂。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int MAXN=500+7;
struct node
{
char c1,c2;
int x,y;
}a[MAXN];
bool map[MAXN][MAXN];
bool vis[MAXN];
int cx[MAXN],cy[MAXN];
int n,m,p;
int dfs(int u)
{
for(int v=1;v<=p;v++)
{
if(map[u][v]&&!vis[v])
{
vis[v]=true;
if(cy[v]==-1||dfs(cy[v]))
{
cx[u]=v;
cy[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
while(~scanf("%d%d%d",&n,&m,&p))
{
memset(map,false,sizeof(map));
for(int i=1;i<=p;i++)
scanf(" %c%d %c%d",&a[i].c1,&a[i].x,&a[i].c2,&a[i].y);
//      for(int i=1;i<=p;i++)
//      printf("%c%d %c%d",a[i].c1,a[i].x,a[i].c2,a[i].y);
for(int i=1;i<=p;i++)
for(int j=i+1;j<=p;j++)
if((a[i].c1==a[j].c2&&a[i].x==a[j].y)||(a[j].c1==a[i].c2&&a[j].x==a[i].y))//不能写成两个条件并存的情况,因为这样的话就只是删除了喜欢和不喜欢互相有矛盾的情况,还有喜欢或者不喜欢的情况
{
map[i][j]=map[j][i]=true;
//          printf("%c%d %c%d\n",a[i].c1,a[i].x,a[i].c2,a[i].y);
//          printf("%c%d %c%d\n",a[j].c1,a[j].x,a[j].c2,a[j].y);
}
memset(cx,-1,sizeof(cx));
memset(cy,-1,sizeof(cy));
int res=0;
for(int i=1;i<=p;i++)
{
memset(vis,false,sizeof(vis));
res+=dfs(i);
}
printf("%d\n",p-res/2);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: