您的位置:首页 > 其它

暑假-二分图-E - Girls and Boys

2015-08-29 18:25 267 查看
题意:有n个学生【从0到n-1】,每个学生都可能与其他学生有关系【或者喜欢其他学生】

现在要找出尽量多的人使得这个集合的任意两人都没关系【互相都不喜欢】

思路:相当于都最大点独立集【集合里任意两点都没有边】,

最大点独立集=顶点数-最大匹配数。

注意:而对于这道题来说,我们可以发现这个浪漫关系是相互的。而我们的建图中,按理来说应该是一边是男的点,

一边是女的点这样连边,但是题目中没说性别的问题。只能将每个点拆成两个点,一个当作是男的点,一个当作是女的点了,

然后连边。由于关系是相互的,这样就造成了边的重复。也就是边集是刚才的二倍,从而导致了最大匹配变成了二倍。

/*
Language:C++ (g++ 4.7.2)
Memory:288KB
Time:220MS
*/
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<vector>
using namespace std;
const int MAXN = 505;
vector<int>map[MAXN];
//邻接矩阵,map[i][j]为1表示Xi喜欢Yj
//用vector可以减少枚举次数,从n降到map[i].size()
int link[MAXN], visy[MAXN];
//link[i]表示最大匹配中与Xi匹配的Y顶点,visy[i]是否访问过
int n;
bool find(int x)
{
	for (int i = 0; i < map[x].size(); i++)//枚举与x学生有关系的学生
	{
		int u = map[x][i];//该学生的编号
		if (!visy[u])//没访问过
		{
			visy[u] = 1;//标记访问
			if (link[u] == -1 || find(link[u]))
			{//如果v没有匹配,或者v已经匹配了,但从cy[v]出发可以找到增广路
				link[u] = x;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	while (scanf("%d",&n)!=EOF)
	{
		memset(link, -1, sizeof(link));
		int m,k,c,ans=0;
		for (int i = 0; i < n; i++)
		{
			scanf("%d: (%d)", &m, &k);
			for (int j = 0; j < k; j++)
			{
				cin >> c;
				map[m].push_back(c);
			}
		}
		for (int i = 0; i < n; i++)
		{
			memset(visy, 0, sizeof(visy));
			if (find(i))//每找到一条增广路,可使得匹配数加1
			{
				ans++;
			}
		}
		printf("%d\n", (n - ans/2));
		//这题的二部图两边集合的点【都是从0到n-1】都一样,所以相当于最大匹配求了两次
		for (int i = 0; i < n; i++)//清除map数组信息
		{
			map[i].clear();
		}
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: