1 3 1 2 –1
output.txt
5
【问题分析】
分层图网络流问题,枚举答案,构造网络流判定。
【建模方法】
首先判断从地球到月球是否存在一条路线,如果不存在那么无解,否则把每个太空站按照每天拆分成d个点,<i,d>表示第i个站第d天。建立附加源S汇T,顺序枚举答案Day。
1、对于第Day天,从S到<0,Day>连接一条容量为无穷大的有向边。
2、从<-1,Day>到T连接一条容量为无穷大的有向边。
3、对于第i个太空船,设第Day-1天在a处,第Day天在b处,从<a,Day-1>到<b,Day>连接一条容量为该太空船容量的有向边。
4、对于第i个太空站,从<i,Day-1>到<i,Day>连接一条容量为无穷大的有向边。
5、求当前网络最大流,如果最大流量大于等于地球上人数K,停止枚举,当前Day值就是答案。
【建模分析】
我们把网络优化问题转化为枚举答案+可行性判定问题。枚举天数,按天数把图分层,因为乘船每坐一站天数都要增加一,把太空船航线抽象成图中的一条边,跨图的两层。由于太空船容量有限,边上也要加上容量限制。除了坐船以外,人还可以在某个空间站等待下一班太空船的到来,所以每个点要与下一层同一点连接一条容量为无穷的边。这样在层限制的图上求出的网络最大流就是在当前天数以内能够从地面到月球的最多的人数,该人数随天数递增不递减,存在单调性。所以可以枚举答案或二分答案,用网络流判定。网络流判定问题更适合枚举答案,而不是二分,因为新增一些点和边只需要在原有的基础上增广,不必重新求网络流。
代码:
const maxn=1000; var e,tot,day,s,t,i,j,x,y,n,m,k:longint; d,last:array[-3..maxn] of longint; state:array[1..maxn] of longint; h:array[1..20] of longint; a:array[1..20,0..20] of longint; side:array[1..100000] of record x,y,c,op,next:longint; end; function point(x,day:longint):longint; begin point:=day*(n+2)+x; end; procedure add(x,y,c:longint); begin inc(e); side[e].x:=x; side[e].y:=y; side[e].c:=c; side[e].op:=e+1; side[e].next:=last[x]; last[x]:=e; inc(e); side[e].x:=y; side[e].y:=x; side[e].c:=0; side[e].op:=e-1; side[e].next:=last[y]; last[y]:=e; end; function bfs:boolean; var head,tail,u,i:longint; begin fillchar(d,sizeof(d),0); head:=0; tail:=1; state[1]:=s; d[s]:=1; repeat inc(head); u:=state[head]; i:=last[u]; while i>0 do with side[i] do begin if (c>0)and(d[y]=0) then begin d[y]:=d[x]+1; inc(tail); state[tail]:=y; if y=t then exit(true); end; i:=next; end; until head>=tail; bfs:=false; end; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; function dfs(x,maxf:longint):longint; var ret,f,i:longint; begin if x=t then exit(maxf); ret:=0; i:=last[x]; while i>0 do with side[i] do begin if (c>0)and(d[y]=d[x]+1) then begin f:=dfs(y,min(c,maxf-ret)); ret:=ret+f; dec(c,f); inc(side[op].c,f); if ret=maxf then break; end; i:=next; end; dfs:=ret; end; begin assign(input,'home.in'); assign(output,'home.out'); reset(input); rewrite(output); readln(n,m,k); for i:=1 to m do begin read(h[i]); read(a[i,0]); for j:=1 to a[i,0] do read(a[i,j]); readln; end; day:=0; s:=-2; t:=-3; add(s,point(0,0),maxlongint); add(point(-1,0),t,maxlongint); while tot<k do begin if day>100 then break; inc(day); add(s,point(0,day),maxlongint); add(point(-1,day),t,maxlongint); for i:=1 to m do begin x:=day mod a[i,0]+1; y:=x-1; if y=0 then y:=a[i,0]; add(point(a[i,y],day-1),point(a[i,x],day),h[i]); end; for i:=-1 to n do add(point(i,day-1),point(i,day),maxlongint); while bfs do tot:=tot+dfs(s,maxlongint); end; if tot>0 then writeln(day) else writeln(0); close(input); close(output); end.