HDU 1068 Girls and Boys【最大独立集】

Girls and Boys

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 8526    Accepted Submission(s): 3909



Problem Description
the second year of the university somebody started a study on the romantic relations between the students. The relation “romantically involved” is defined between one girl and one boy. For the study reasons it is necessary to find out the maximum set satisfying the condition: there are no two students in the set who have been “romantically involved”. The result of the program is the number of students in such a set.

The input contains several data sets in text format. Each data set represents one set of subjects of the study, with the following description:

the number of students
the description of each student, in the following format
student_identifier:(number_of_romantic_relations) student_identifier1 student_identifier2 student_identifier3 ...
or
student_identifier:(0)

The student_identifier is an integer number between 0 and n-1, for n subjects.
For each given data set, the program should write to standard output a line containing the result.
 

Sample Input
  
  
7 0: (3) 4 5 6 1: (2) 4 6 2: (0) 3: (0) 4: (2) 0 1 5: (1) 0 6: (2) 0 1 3 0: (2) 1 2 1: (1) 0 2: (1) 0
 

Sample Output
  
  
5 2
 

Source

题目链接。


题目大意:
大二的时候,有些人开始研究男女间的恋爱关系。
研究者想要找出没有恋爱关系的同学的最大集合,
也就是在此集合中,任意两个同学都不存在恋爱关系。
得到结果就是这个集合中学生的数量。


解题思路:
求二分图的最大独立集。 
可以邻接表或邻接矩阵构图,但邻接矩阵内存开销大。
因为题目只给出学生的个数,未明确给出第i个学生是男生还是女生,所以要遍历所有学生。
因此相同的增广路求了两遍,最后得到的最大匹配count要除以2。


例如测试样例一: 
7
0: (3) 4 5 6
1: (2) 4 6
2: (0)
3: (0)
4: (2) 0 1
5: (1) 0
6: (2) 0 1


用匈牙利算法得最大匹配的边为:
<0,5>,<5,0>,<1,4>,<4,1> 
题目要求:0和5,1和4不能属于同一顶点集(同一性别),
则存在对称边,也就是相同的增广路求了两遍。
所以得到的最大匹配要除以2。


最后得到的最大独立集为 A={2,3,4,5,6} (假设0,1,2,3为男生,4,5,6为女生就好理解了)
答案为5。 


/*邻接矩阵(内存开销大)*/ 
#include <cstdio>
#include <cstring>
const int maxn = 1010;
bool rom[maxn][maxn],vis[maxn];
int stu[maxn];
int n;
void init()
{
	int i,j,nu,s,e;
	memset(rom,0,sizeof(rom));
	memset(stu,-1,sizeof(stu)); 	//因为存在0元素,所以stu[]初始为-1 
	for(i=0;i<n;++i)
	{
		scanf("%d: (%d)",&s,&nu);	//注意输入 
		for(j=0;j<nu;++j)
		{
			scanf("%d",&e);
			rom[s][e]=true;
		}
	}
}
bool find(int p)
{
	int i;
	for(i=0;i<n;++i)
	{
		if(rom[p][i]==true&&!vis[i])
		{
			vis[i]=true;
			if(stu[i]==-1||find(stu[i]))
			{
				stu[i]=p;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int i,count;
	while(scanf("%d",&n)==1)
	{
		init();
		count = 0;
		for(i=0;i<n;++i)
		{
			memset(vis,0,sizeof(vis));
			if(find(i))
				count++;
		}
		printf("-%d-%d-",count,count/2);
		printf("%d\n",n-count/2);
	}
	return 0;
}




/*邻接表*/
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1010;
vector<int > rom[maxn];		//用vector建邻接表 
bool vis[maxn];
int stu[maxn];
int n;
void init()
{
	int i,j,k,nr,s,e;
	for(i=0;i<=n;++i)
	{
		rom[i].clear();
		stu[i]=0; 
	}
	for(i=0;i<n;++i)
	{
		scanf("%d: (%d)",&s,&nr);
		rom[s+1].push_back(0);		//每个数组的第一个值赋为0,大小+1 
		for(j=0;j<nr;++j)
		{
			scanf("%d",&e);
			rom[s+1].push_back(e+1);	//令下标从1开始 
		}
	}
}
bool find(int p)
{
	int i,k;
	for(i=1;i<rom[p].size();++i)	//注意下标从1开始(rom[p][0]==0),且不能等于(因为数组的下标从0开始) 
	{
		k=rom[p][i];
		if(!vis[k])		//因为是邻接表,所以不需要如邻接矩阵一样判断rom[p][i] 
		{
			vis[k]=true;
			if(stu[k]==0||find(stu[k]))
			{
				stu[k]=p;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int i,count;
	while(scanf("%d",&n)==1)
	{
		init();
		count=0;
		for(i=1;i<=n;++i)				//注意下标从1开始 
		{
			memset(vis,0,sizeof(vis));
			if(find(i))
				count++;
		}
		printf("%d\n",n-count/2);		//因为关系是对称的,相同增光路遍历了两遍,所以最大匹配为count/2 
	}
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值