SGU 242 Student’s Morning

二分图匹配/网络流

把每个学校拆成两个点中间连一条容量下界为2的边,然后求可行流就行了。由于问题特殊,可以用二分图匹配来解决:把每个学校拆成两个点,如果一个学生愿意去一个学校,将这个学生和这个学校拆成的两个点各连一条边。利用匈牙利算法求二分图最大匹配,如果最大匹配数恰好为2k则有解,按照匹配方案输出即可,否则无解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
 
using namespace std;
 
struct edge
{
	int v;
	edge *next;
	edge(int v,edge *next):v(v),next(next) {}
} *e[222];
int match[222];
bool u[222];
 
bool findAugmentPath(int v)
{
	for(edge *t=e[v];t;t=t->next)
		if(!u[t->v])
		{
			u[t->v]=true;
			if(!match[t->v]||findAugmentPath(match[t->v]))
			{
				match[t->v]=v;
				return true;
			}
		}
	return false;
}
 
int main()
{
	int n,k,t,p;
	scanf("%d%d",&n,&k);
	if(k*2>n)
	{
		puts("NO");
		return 0;
	}
	for(int i=1;i<=n;++i)
		for(scanf("%d",&t);t;--t)
		{
			scanf("%d",&p);
			e[i]=new edge(p,e[i]);
			e[i]=new edge(k+p,e[i]);
		}
	int total=0;
	for(int i=1;i<=n;++i)
	{
		memset(u,false,sizeof(u));
		if(findAugmentPath(i)) ++total;
	}
	if(total==(k<<1))
	{
		puts("YES");
		for(int i=1;i<=k;++i) printf("2 %d %d\n",match[i],match[k+i]);
	}
	else puts("NO");
	return 0;
}

Leave a Reply