【POJ1469】Courses-二分图最大匹配

测试地址:Courses

题目大意:有P门课程和N个学生,要求从这些学生中取出P个组成委员会,要求:(1)委员会中的每个学生都代表不一样的课程(一个学生上一门课程,他就可以代表这门课程)。(2)委员会中每门课程都有不同的学生代表。问存不存在这样的委员会组建方案。

做法:裸的二分图最大匹配,这里直接套Hungary(匈牙利)算法即可。

2017.3.7更新:用理论上更优的Hopcroft-Karp算法又做了一遍,一并贴在这里。

以下是本人代码:

Hungary(匈牙利)算法:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int T,n,p,tot=0,match,first[110],mat[310];
struct {int v,next;} e[100010];
bool used[310];

void insert(int a,int b)
{
  e[++tot].v=b;
  e[tot].next=first[a];
  first[a]=tot;
}

bool crosspath(int x) //返回一个布尔值,表示存不存在从x出发的交错链
{
  for(int i=first[x];i;i=e[i].next)
  {
    int j=e[i].v;
	if (!used[j])
	{
	  used[j]=1;
	  if (mat[j]==0||crosspath(mat[j]))
	  {
	    mat[j]=x;
		return 1;
	  }
	}
  }
  return 0;
}

void hungary() //Hungary(匈牙利)算法
{
  for(int i=1;i<=p;i++)
  {
    memset(used,0,sizeof(used));
    if (crosspath(i))
	  match++;
  }
}

int main()
{
  scanf("%d",&T);
  while(T--)
  {
    scanf("%d%d",&p,&n);
	memset(first,0,sizeof(first));
	memset(mat,0,sizeof(mat));
	match=tot=0;
	for(int i=1;i<=p;i++)
	{
	  int cnt;
	  scanf("%d",&cnt);
	  while(cnt--)
	  {
	    int a;
		scanf("%d",&a);
		insert(i,a);
	  }
	}
	if (p>n) {printf("NO\n");continue;} //课程数多于学生数,不可能有满足条件的方案
	hungary();
	if (p==match) printf("YES\n");
	else printf("NO\n");
  }
  
  return 0;
}

Hopcroft-Karp算法:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#define inf 999999999
using namespace std;
int p,n,dis,T;
int bmap[110][310];
int cx[110],cy[310],dx[110],dy[310];
bool vis[310];

bool searchpath()
{
  queue<int> q;
  dis=inf;
  memset(dx,-1,sizeof(dx));
  memset(dy,-1,sizeof(dy));
  for(int i=1;i<=p;i++)
  {
    if (cx[i]==-1)
	{
	  q.push(i);
	  dx[i]=0;
	}
  }
  while(!q.empty())
  {
    int u=q.front();q.pop();
	if (dx[u]>dis) break;
	for(int i=1;i<=n;i++)
	{
	  if (bmap[u][i]&&dy[i]==-1)
	  {
	    dy[i]=dx[u]+1;
		if (cy[i]==-1) dis=dy[i];
		else
		{
		  dx[cy[i]]=dy[i]+1;
		  q.push(cy[i]);
		}
	  }
	}
  }
  return dis!=inf;
}

int findpath(int u)
{
  for(int i=1;i<=n;i++)
  {
    if (!vis[i]&&bmap[u][i]&&dy[i]==dx[u]+1)
	{
	  vis[i]=1;
	  if (cy[i]!=-1&&dy[i]==dis)
	  {
	    continue;
	  }
	  if (cy[i]==-1||findpath(cy[i]))
	  {
	    cy[i]=u,cx[u]=i;
	    return 1;
	  }
	}
  }
  return 0;
}

int maxmatch()
{
  int ans=0;
  memset(cx,-1,sizeof(cx));
  memset(cy,-1,sizeof(cy));
  while(searchpath())
  {
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=p;i++)
	{
	  if (cx[i]==-1)
	  {
	    ans+=findpath(i);
	  }
	}
  }
  return ans;
}

int main()
{
  scanf("%d",&T);
  while(T--)
  {
    scanf("%d%d",&p,&n);
	memset(bmap,0,sizeof(bmap));
	for(int i=1,k;i<=p;i++)
	{
	  scanf("%d",&k);
	  for(int j=1,a;j<=k;j++)
	  {
	    scanf("%d",&a);
		bmap[i][a]=1;
	  }
	}
	
	if (maxmatch()==p) printf("YES\n");
	else printf("NO\n");
  }
  
  return 0;
}


posted @ 2016-09-18 22:29  Maxwei_wzj  阅读(98)  评论(0编辑  收藏  举报