您的位置:首页 > 其它

SGU 242(MaxFlow)

2015-08-20 20:12 267 查看

题意简述

N个学生,K所学校(0≤N,K≤200),给定每个学生喜爱的若干所学校。每个学生仅可以选择一所他喜爱的学校(也可不选),问是否存在一种选择方案使每所学校至少被2个学生选择,若存在,请打印任意一种方案。

建 图

1.建立源点S,汇点T。

2.从源点S向每个学生连一条容量为 1 的边。(限制每个学生的选择)

3.从每所学校向汇点T连一条容量为 2 的边。(满流即可)

4.从每个学生向其喜爱的学校连一条容量为 1 的边。

算法实现

直接跑Dinic最大流算法

若最大流为2∗K,则存在一种选择方案

输出方案:若一条从学生流向学校的边容量为0,则该边被选择,即该学生选择了该校

Hint

如果你RE或WA了很久,可以向我要SPJ和随机数据生成器。

蠢蠢的博主因为反向边表示错误,调了很久……

type
edge=record
re,next,cap:longint;
end;
var
i,j:longint;
cnt,n,k,s,t,ans,xc,x,tmp,zhi:int64;
e:array[0..100000] of edge;
f,d,q:array[0..600] of longint;
vs:array[0..600] of boolean;
a:array[0..600,0..2] of longint;
boo:array[0..600] of boolean;

procedure add(x,y,tmp:longint);
begin
inc(cnt);
with e[cnt] do
begin
re:=y;
next:=f[x];
cap:=tmp;
end;
f[x]:=cnt;
end;

procedure bfs;
var
head,tail,x,tmp:longint;
begin
fillchar(vs,sizeof(vs),0);
fillchar(d,sizeof(d),0);
head:=1;tail:=1;q[1]:=s;vs[s]:=true;
while head<=tail do
begin
x:=q[head];tmp:=f[x];
while tmp<>0 do
begin
with e[tmp] do
begin
if (cap<>0)and not vs[re] then
begin
inc(tail);q[tail]:=re;
vs[re]:=true;d[re]:=d[x]+1;
end;
end;
tmp:=e[tmp].next;
end;
inc(head);
end;
end;

function min(x,y:int64):int64;
begin
if x<y then min:=x else min:=y;
end;

function dfs(x,rec:longint):longint;
var
ret,dd,tmp:longint;
begin
ret:=0;
if x=t then begin dfs:=rec;exit;end;
tmp:=f[x];
while (tmp<>0)and(rec<>0) do
begin
if (d[e[tmp].re]=d[x]+1)and(e[tmp].cap<>0) then
begin
dd:=dfs(e[tmp].re,min(e[tmp].cap,rec));
if dd<>0 then
begin
dec(rec,dd);inc(ret,dd);
dec(e[tmp].cap,dd);inc(e[(tmp-1) xor 1 +1].cap,dd);
if rec=0 then begin dfs:=ret; exit; end;
end;
end;
tmp:=e[tmp].next;
end;
dfs:=ret;
if ret=0 then d[x]:=-1;
end;

procedure dinic;
begin
while true do
begin
bfs;
if not vs[t] then exit;
inc(ans,dfs(s,5000000));
end;
end;

begin
readln(n,k);
s:=500;t:=501;cnt:=0;
for i:=1 to n do
begin
read(xc);
add(s,i,1);add(i,s,0);
for j:=1 to xc do
begin
read(x);add(i,x+n,1);add(x+n,i,0);
end;
end;
for i:=1 to k do
begin add(i+n,t,2);add(t,n+i,0);end;

ans:=0;
dinic;

if ans<>2*k then writeln('NO')
else
begin
for i:=1 to n do
begin
tmp:=f[i];
while tmp<>0 do
begin
with e[tmp] do
if (cap=0)and(re<>s) then
begin
inc(a[re-n,0]);a[re-n,a[re-n,0]]:=i;
break;
end;
tmp:=e[tmp].next;
end;
end;
writeln('YES');
for i:=1 to k do writeln('2 ',a[i,1],' ',a[i,2]);
end;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sgu