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.
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-01-13
  • 2021-05-18
  • 2021-09-06
  • 2021-09-14
  • 2021-08-06
  • 2022-01-18
猜你喜欢
  • 2021-06-26
  • 2021-06-14
  • 2022-01-06
  • 2021-11-26
  • 2021-04-26
  • 2021-05-06
相关资源
相似解决方案