Courses HDU1083(二分图的匹配)

题目http://acm.hdu.edu.cn/showproblem.php?pid=1083

描述:有p门的课,每门课都有若干学生,现在要为每个课程分配一名课代表,每个学生只能担任一门课的课代表,如果每个课都能找到课代表,则输出"YES",否则"NO"。

思想:采用二分图的最大匹配,对课程—学生关系建立一个图,进行二分图的最大匹配,如果最大匹配数==课程数,说明能够满足要求,否则不能。每个课程轮流选择课代表,从头遍历n学生,如果该学生还未担任任何课程的课代表或者一个学生担任的课代表的那个课程可以有其他人来担任课代表,那么该课程的课代表就是他了。用递归,不断进行匹配。保证最大匹配。

 

实现代码:

#include<iostream>
using namespace std;

int cs[305][305];//课程与学生的关心,cs[i][j]为1时表示j有选第i个课程。
int link[305];//表示学生担任课代表的课程。link[i]=j表示j课程的课代表是i
bool has[305];//表示学生是否被考虑过能不能当某个课的课代表。

int p,n;

//分配x课程的课代表
int fenpei(int x)
{
	int i;
	for(i=1;i<=n;i++)
	{
		//如果i学生还没有担任课代表而且他有选x这个课。
		if(!has[i]&&cs[x][i]==1)
		{
			has[i]=1;
			//i还未担任某个课程的课代表或者其担任的课代表还可以找到别人担任。
			if(!link[i]||fenpei(link[i]))
			{
				link[i]=x;
				return 1;
			}
		}
	}
	return 0;
}

int main(int argc, char* argv[])
{
	int i,t,x,sum,m;
	cin>>t;
	while(t--)
	{
		cin>>p>>n;
		memset(cs,0,sizeof(cs));
		for(i=1;i<=p;i++)
		{
			cin>>m;
			while(m--)
			{
				cin>>x;
				cs[i][x]=1;
			}
		}
		sum=0;
		memset(link,0,sizeof(link));
		//为每个课程分配课代表
		for(i=1;i<=p;i++)
		{
			//每次为一个课程选择课代表的时候,每个学生都要从头考虑,直到找到合适的课代表为止。
			memset(has,0,sizeof(has));
			if(fenpei(i)) sum++;
		}
		if(sum==p) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;


	}
	return 0;
}

这到题目类似于婚姻问题,有n个男的和n个女的,每个男的对每个女的有一个满意度,女的也是一样,要求你为他们配对,使他们的婚姻比较稳定(如果一个男的和一个女的对对方的满意度都比对自己被分配到对象的满意度要高,那样叫做不稳定)。也同样用到二分图的最大匹配,可以这样去做,每个男的轮流去向女的求婚,女的可以选择接受或者拒绝,当她对一个比她现在分配到的对象更心仪的时候,她选择放弃当前的被分配的,而选择当前那个。

你可能感兴趣的:(Courses HDU1083(二分图的匹配))