hihocoder 1393 : 网络流三·二分图多重匹配

标签: hihocoder 网络流 二分图


描述

学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来。
小Hi和小Ho作为班上的班干部,统计分配比赛选手的重任也自然交到了他们手上。
已知小Hi和小Ho所在的班级一共有N名学生(包含小Hi和小Ho),编号依次为1..N。
运动会一共有M项不同的比赛,编号为1..M。第i项比赛每个班需要派出m[i]名选手参加。
根据小Hi和小Ho的统计,编号为i的学生表示最多同时参加a[i]项比赛,并且给出他所擅长的b[i]项比赛的编号。
小Hi和小Ho希望将每个学生都安排到他所擅长的比赛项目,以增加夺冠的可能性。同时又要考虑满足每项比赛对人数的要求,当然给一个学生安排的比赛项目也不能超过他愿意参加的比赛项目数量。
根据统计的结果,小Hi和小Ho想知道能否有一个合适的安排,同时满足这些条件。
提示:二分图多重匹配

输入

第1行:1个整数T,表示一共有T(2≤T≤5)组数据,每组数据按如下格式给出:
第1行:2个正整数N,M。1≤N≤100,1≤M≤100。
第2行:M个整数,第i个数表示第i个项目需要的选手数量m[i]。1≤m[i]≤N。
第3..N+2行:若干整数,第i+2行表示编号为i的学生的信息。先是a[i],b[i],接下来b[i]个整数,表示其所擅长的b[i]个项目。1≤a[i]≤M

输出

第1..T行:第i行表示第i组数据能否满足要求,若能够输出"Yes",否则输出"No"。

样例输入

2
4 3
1 2 2
1 2 1 2
2 2 1 3
1 1 2
1 2 2 3
4 3
2 2 2
1 2 1 2
2 2 1 3
1 1 2
1 2 2 3

样例输出

Yes
No

分析

首先建立假想的源点和汇点。
对于第(i)个人来说,他只能参加(a_i)个项目,所以将源点 (s)(i) 的容量设置为(a_i)
对于第(i)个项目来说,只能有(m_i)个人参加,所以将(n+i)向汇点的容量设置为(m_i)
如果第(i)个人擅长(j)项目,那么把(i)(j)的容量设置为(1).
然后跑最大流即可。
(PS:为什么又没有卡Ford-Fulkerson的数据?)

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const ll MOd=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=150;
struct Edge
{
	int v,nxt,c,f;
}e[100050];
int h[maxn*2],tot;
void addEdge(int x,int y,int w){
	e[++tot]=(Edge){y,h[x],w,0};
	h[x]=tot;
}
int n,m,s,t;
bool vis[maxn*2];
ll dfs(int x,ll flow){
	if(vis[x]||flow==0) return 0;
	vis[x]=true;
	if(x==t) return flow;
	ll ans=0;
	for (int i = h[x]; i ; i=e[i].nxt)
	{
		ll t=min(flow,(ll)e[i].c-e[i].f);
		if(t>0 && (ans=dfs(e[i].v,t))){
			e[i].f+=ans;
			return ans;
		}
		t=min(flow,(ll)e[i^1].f);
		if(t>0 && (ans=dfs(e[i].v,t))){
			e[i^1].f-=ans;
			return ans;
		}
	}
	return 0;
}
int main(int argc, char const *argv[])
{
	int T;
	scanf("%d", &T);
	while(T--){
		scanf("%d%d", &n,&m);
		s=0,t=n+m+1;
		for (int i = 0; i <= t; ++i)
		{
			h[i]=0;
		}
		tot=1;
		ll M=0;
		for (int i = n+1; i <= n+m; ++i)
		{
			int w;
			scanf("%d", &w);
			addEdge(i,t,w);
			addEdge(t,i,0);
			M+=w;
		}
		for (int i = 1; i <= n; ++i)
		{
			int a,b;
			scanf("%d%d", &a,&b);
			addEdge(s,i,a);
			addEdge(i,s,0);
			while(b--){
				int x;
				scanf("%d", &x);
				addEdge(i,x+n,1);
				addEdge(x+n,i,0);
			}
		}
		ll sum=0,flow=0;
		memset(vis,false,sizeof vis);
		while(flow=dfs(s,inf)){
			sum+=flow;
			memset(vis,false,sizeof vis);
		}
		bool ans=true;
		if(sum!=M) ans=false;
		printf(ans?"Yes
":"No
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/sciorz/p/9037841.html