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.
相关文章推荐
- SGU200 Cracking RSA
- SGU201 Non Absorbing DFA
- SGU 181 X-Sequence(傻逼题)
- SGU 477 doors
- sgu 223
- sgu 259
- SGU 495 Kids and Prizes (概率DP)
- SGU101 DFS
- SGU103 最短路 Shortest Path
- SGU102 水题 An easy problem
- SGU105 水题 An easy problem
- SGU104 DP
- SGU107 水题 Easy
- SGU106 Extend GCD
- SGU109 奇偶性 problem of parity
- SGU108 数学题 Math
- SGU111 大数开方 Evolution
- SGU110 计算几何 Computational Geometry
- SGU113 水题 Easy Problem
- SGU112 水题 Easy