wikioi1034 家园
这是一道神奇的网络流。具体详细的题解以及代码可以去Orz这个大神的博客。
传送门:http://blog.csdn.net/lytning/article/details/23034379
简单地说,就是要建立一个模型,就是把每个点(包括地球和月球)都分成无数多个点……比如第j个时刻的地球,就用地球i号表示,第i个中转站就用i中转站j表示。(处理是把月球-1自动改为n+1吧)。把飞船看成是边。然后就是神奇的跑一遍sap看是否能运那么多人,不行再扩展一层节点在跑一遍……orz语言能力不好还是去看上面那个大神的博客吧。最后把数组开大!把记录边的数组开到很大很大……不然就和我一样wa了好多好多次……或者把time控制小一点……比如等于100是就不要找了根本找不到的,这样时间差不多就剩下100ms(time为200要跑700ms)……
type arr=record toward,cap,next:longint; end;var edge:array[0..100000]of arr; d,num,first,cur,h:array[0..5000]of longint; c:array[0..50,0..10000]of longint; ss,tot,sum,st,s,t,i,j,k,n,m,kk,time,flow,leftk:longint; function cal(i,j:longint):longint; begin exit((n*2)*j+i+2); end; function min(x,y:longint):longint; begin if x>y then exit(y); exit(x); end; procedure add(i,j,k:longint); begin edge[tot].toward:=j; edge[tot].cap:=k; edge[tot].next:=first[i]; first[i]:=tot; inc(tot); end; procedure addedge(i,j,k:longint); begin add(i,j,k); add(j,i,0); end; function sap(v,flow:longint):longint; var rec,ret,i,j:longint; begin if v=st then exit(flow); rec:=0; i:=cur[v]; while i<>-1 do begin j:=edge[i].toward; if (edge[i].cap>0) and (d[v]=d[j]+1) then begin ret:=sap(j,min(flow-rec,edge[i].cap)); dec(edge[i].cap,ret); inc(edge[i xor 1].cap,ret); cur[v]:=i; inc(rec,ret); if rec=flow then exit(flow); end; i:=edge[i].next; end; dec(num[d[v]]); if num[d[v]]=0 then d[ss]:=sum; inc(d[v]); inc(num[d[v]]); cur[v]:=first[v]; exit(rec); end; function maxflow:longint; var flow:longint; begin fillchar(num,sizeof(num),0); fillchar(d,sizeof(d),0); for i:=0 to sum do cur[i]:=first[i]; num[0]:=sum; flow:=0; while d[ss]<sum do inc(flow,sap(ss,maxlongint)); exit(flow); end; procedure more(time:longint); var i,j,k:longint; begin inc(sum,n+2); inc(num[0],n+2); if time=0 then addedge(ss,cal(s,time),kk); addedge(cal(t,time),st,maxlongint); if time>0 then begin for i:=s to n do addedge(cal(i,time-1),cal(i,time),maxlongint); addedge(cal(t,time-1),cal(t,time),maxlongint); for i:=1 to m do begin j:=time mod c[i,0]+1; k:=time mod c[i,0]; if k=0 then k:=c[i,0]; addedge(cal(c[i,k],time-1),cal(c[i,j],time),h[i]); end; end; end; begin readln(n,m,kk); leftk:=kk; fillchar(edge,sizeof(edge),0); fillchar(num,sizeof(num),0); for i:=0 to 200*(n+2) do first[i]:=-1; tot:=0; s:=0; t:=n+1; ss:=0; st:=1; sum:=2; num[0]:=2; for i:=1 to m do begin read(h[i],c[i,0]); for j:=1 to c[i][0] do begin read(c[i,j]); if c[i,j]=-1 then c[i,j]:=n+1; end; readln; end; time:=0; while time<200 do begin more(time); flow:=0; inc(flow,maxflow); dec(leftk,flow); if leftk<=0 then begin writeln(time); break; end; inc(time); end; if time=200 then writeln('0'); end.