zoukankan      html  css  js  c++  java
  • 【以前的空间】网络流合集

    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

    vijos 1653 疯狂方格取数

       zkw处理负边上跪了很久。网上少有资料

    const maxn= 100000;
    
    type
    
     edgetype=record
    
      toward,cap,cost,next:longint;
    
     end;
    
    var
    
     edge:array[0..maxn] of edgetype;
    
     map:array[1..1000,1..1000,0..1] of longint;
    
     q,first,slack,d,dist:array[0..maxn] of longint;
    
     pd:array[0..maxn] of boolean;
    
     i,j,n,m,ss,st,tot,k,x,cnt,point,mincost:longint;
    
    
    
    function min(x,y:longint):longint;
    
    begin
    
     if x<y then exit(x) else exit(y);
    
    end;
    
    
    
    procedure add(i,j,k,l:longint);
    
    begin
    
     edge[tot].toward:=j;
    
     edge[tot].cap:=k;
    
     edge[tot].cost:=l;
    
     edge[tot].next:=first[i];
    
     first[i]:=tot;
    
     inc(tot);
    
    end;
    
    
    
    procedure addedge(i,j,k,l:longint);
    
    begin
    
     add(i,j,k,l);
    
     add(j,i,0,-l);
    
    end;
    
    
    
    procedure spfa;
    
    var head,tail,i,j,tmp,value:longint;
    
    begin
    
     fillchar(pd,sizeof(pd),false);
    
     for i:= ss to st do d[i]:=maxlongint;
    
     head:=1;
    
     tail:=1;
    
     q[1]:=ss;
    
     pd[ss]:=true;
    
     d[ss]:=0;
    
     while head<=tail do
    
      begin
    
       j:=q[head];
    
       i:=first[j];
    
       while i<>-1 do
    
        begin
    
         tmp:=edge[i].toward;
    
         value:=edge[i].cost;
    
         if (edge[i].cap>0) and (d[tmp]>d[j]+value) then
    
          begin
    
           d[tmp]:=d[j]+value;
    
            if not pd[tmp] then
    
             begin
    
              inc(tail);
    
              if tail=maxn then tail:=1;
    
              q[tail]:=tmp;
    
              pd[tmp]:=true;
    
             end;
    
          end;
    
         i:=edge[i].next;
    
        end;
    
       inc(head);
    
       if head=maxn then head:=1;
    
       pd[j]:=false;
    
      end;
    
    end;
    
    
    
    procedure dfs(v:longint);
    
    var i,value,tmp:longint;
    
    begin
    
     pd[v]:=true;
    
     i:=first[v];
    
     while i<>-1 do
    
      begin
    
       tmp:=edge[i].toward;
    
       value:=edge[i].cost;
    
       if (edge[i].cap>0) and (not pd[tmp]) and (d[tmp]=d[v]+value) then
    
        begin
    
         dist[tmp]:=dist[v]-value;
    
         dfs(tmp);
    
        end;
    
      i:=edge[i].next;
    
      end;
    
    end;
    
    
    
    function aug(v,flow:longint):longint;
    
    var rec,ret,i,tmp,value:longint;
    
    begin
    
     if v=st then
    
      begin
    
       inc(mincost,flow*(dist[st]-dist[ss]));
    
       exit(flow);
    
      end;
    
     rec:=0;
    
     i:=first[v];
    
     pd[v]:=true;
    
     while i<>-1 do
    
      begin
    
       tmp:=edge[i].toward;
    
       value:=edge[i].cost;
    
       if (not pd[tmp]) and (edge[i].cap>0) then
    
        if dist[v]=dist[tmp]+value then
    
         begin
    
          ret:=aug(tmp,min(flow-rec,edge[i].cap));
    
          dec(edge[i].cap,ret);
    
          inc(edge[i xor 1].cap,ret);
    
          inc(rec,ret);
    
          if rec=flow then exit(flow);
    
         end
    
        else slack[tmp]:=min(slack[tmp],dist[tmp]+value-dist[v]);
    
       i:=edge[i].next;
    
      end;
    
     exit(rec);
    
    end;
    
    
    
    function relabel:boolean;
    
    var i,delta:longint;
    
    begin
    
     delta:=maxlongint;
    
     for i:= ss to st do if not pd[i] then delta:=min(delta,slack[i]);
    
     if delta=maxlongint then exit(false);
    
     for i:= ss to st do if pd[i] then inc(dist[i],delta);
    
     exit(true);
    
    end;
    
    
    
    procedure init;
    
    begin
    
     readln(k,m,n);
    
     cnt:=m*n;
    
     ss:=0;
    
     st:=cnt*2+1;
    
     tot:=0;
    
     point:=0;
    
     for i:= ss to st do first[i]:=-1;
    
     for i:=1 to n do
    
      for j:= 1 to m do
    
       begin
    
        read(x);
    
        inc(point);map[i,j,0]:=point;
    
        inc(point);map[i,j,1]:=point;
    
        addedge(map[i,j,0],map[i,j,1],1,-x);
    
        addedge(map[i,j,0],map[i,j,1],maxlongint,0);
    
       end;
    
     addedge(ss,map[1,1,0],k,0);
    
     addedge(map[n,m,1],st,k,0);
    
     for i:=1 to n do
    
      for j:= 1 to m do
    
       begin
    
        if i+1<=n then addedge(map[i,j,1],map[i+1,j,0],maxlongint,0);
    
        if j+1<=m then addedge(map[i,j,1],map[i,j+1,0],maxlongint,0);
    
       end;
    
    end;
    
    
    
    procedure costflow;
    
    begin
    
     spfa;
    
     fillchar(pd,sizeof(pd),false);
    
     fillchar(dist,sizeof(dist),0);
    
     dfs(ss);
    
     repeat
    
      for i:= ss to st do slack[i]:=maxlongint;
    
      repeat
    
       fillchar(pd,sizeof(pd),false);
    
      until aug(ss,maxlongint)<=0;
    
     until not relabel;
    
    end;
    
    
    
    Begin
    
     init;
    
     costflow;
    
     writeln(mincost);
    
    end.
    View Code

    vijos 1726 美食节(费用流)

        很明显是一道费用流,如果用常规的方法,把每个厨师每个时刻拆出来的话,由于点太多会爆于是我们考虑了这样一个事实,每个厨师并不需要把他每个时刻的点都扩展出来,一个厨师只有当他做完一个菜是才去考虑让他多做一个菜,这样的话由于一种只有sum(=∑p[i])道菜,所有整个图实际需要的点数就是源点汇点(2个),菜(n个),厨师(m个)以及扩展出来的厨师(sum个,实际只需sum-m,但为了方法我们不妨多几个点)。一开始源点连每道菜连一条容量为菜需求量费用为0的边,汇点和每个厨师连一条容量为1费用为0的边,然后把第i个厨师与第j道菜连一条容量为1费用为厨师做这道菜的时间的边。这样就是一个初始图。跑spfa(由于一次一定是做一道菜,所以就可以省点记录此次增广的流量),然后每次增广后必然会有一个厨师做出了某道菜,这是我们就扫一遍判断是哪个厨师做了菜(开个last数组记录每个厨师当前点与汇点的边,判断哪个厨师的最后一条边容量为0),然后开个chef表示这个厨师至今做了多少道菜。重新增加一个点,这个点与每道菜连一条容量为1费用为(这个厨师做这道菜的时间*这个厨师一共做了多少道菜),然后这个点再与汇点连一条容量为1费用为0的边。开个time计菜,等time=sum时就说明做完了,输出这时的费用就是答案了。

    const maxn=300000;
    
    type
    
     edgetype=record
    
      toward,cap,cost,next:longint;
    
     end;
    
    var
    
     edge:array[0..maxn] of edgetype;
    
     minflow,pre,first,q,dist:array[0..maxn] of longint;
    
     pd:array[0..maxn] of boolean;
    
     p:array[1..40] of longint;
    
     data:array[1..40,1..100] of longint;
    
     chef:array[1..100] of longint;
    
     last:array[1..100] of longint;
    
     i,j,s,t,n,m,tot,cnt,time,x:longint;
    
    
    
    function min(x,y:longint):longint;
    
    begin
    
     if x<y then exit(x) else exit(y);
    
    end;
    
    
    
    procedure add(i,j,k,l:longint);
    
    begin
    
     edge[tot].toward:=j;
    
     edge[tot].cap:=k;
    
     edge[tot].cost:=l;
    
     edge[tot].next:=first[i];
    
     first[i]:=tot;
    
     inc(tot);
    
    end;
    
    
    
    procedure addedge(i,j,k,l:longint);
    
    begin
    
     add(i,j,k,l);
    
     add(j,i,0,-l);
    
    end;
    
    
    
    function spfa:boolean;
    
    var tmp,value,i,j,head,tail:longint;
    
    begin
    
     fillchar(pd,sizeof(pd),false);
    
     for i:=0 to t do dist[i]:=maxlongint;
    
     head:=1;
    
     tail:=1;
    
     q[tail]:=s;
    
     pd[s]:=true;
    
     dist[s]:=0;
    
     while head<=tail do
    
      begin
    
       j:=q[head];
    
       i:=first[j];
    
       while i<>-1 do
    
        begin
    
         tmp:=edge[i].toward;
    
         value:=edge[i].cost;
    
         if (edge[i].cap>0) and (dist[tmp]>dist[j]+value) then
    
          begin
    
           dist[tmp]:=dist[j]+value;
    
           pre[tmp]:=i;
    
           if not pd[tmp] then
    
            begin
    
             inc(tail);
    
             q[tail]:=tmp;
    
             pd[tmp]:=true;
    
            end;
    
          end;
    
         i:=edge[i].next;
    
        end;
    
       inc(head);
    
       pd[j]:=false;
    
      end;
    
     if dist[t]=maxlongint then exit(false) else exit(true);
    
    end;
    
    
    
    function mcmf:longint;
    
    var u,cost:longint;
    
    begin
    
     cost:=0;
    
     while time<cnt do
    
      begin
    
       if not spfa then break;
    
       u:=t;
    
       while u<>s do
    
        begin
    
         dec(edge[pre[u]].cap);
    
         inc(edge[pre[u] xor 1].cap);
    
         u:=edge[pre[u] xor 1].toward;
    
        end;
    
       inc(cost,dist[t]);
    
       inc(time);
    
       for i:= 1 to m do
    
        if edge[last[i]].cap=0 then
    
         begin
    
          x:=i;
    
          break;
    
         end;
    
       inc(chef[x]);
    
       for i:=1 to n do
    
         addedge(i,n+m+time,1,data[i,x]*chef[x]);
    
       addedge(n+m+time,t,1,0);
    
       last[x]:=tot-2;
    
      end;
    
     exit(cost);
    
    end;
    
    
    
    procedure init;
    
    begin
    
     tot:=0;
    
     time:=0;
    
     cnt:=0;
    
     read(n,m);
    
     for i:=1 to n do
    
      begin
    
       read(p[i]);
    
       inc(cnt,p[i]);
    
      end;
    
     for i:= 1 to n do
    
      for j:= 1 to m do
    
       read(data[i,j]);
    
     s:=n+m+cnt+1; 
    
     t:=s+1;
    
     for i:= 0 to t do first[i]:=-1;
    
     for i:=1 to n do
    
      addedge(s,i,p[i],0);
    
     for i:=1 to n do
    
      for j:= 1 to m do
    
       addedge(i,j+n,1,data[i,j]);
    
     for i:= 1 to m do chef[i]:=1;
    
     for i:=1 to m do
    
      begin
    
       addedge(n+i,t,1,0);
    
       last[i]:=tot-2;
    
      end;
    
    end;
    
    
    
    Begin
    
     init;
    
     writeln(mcmf);
    
    End.
    View Code

    vijos 1621 终极情报网(费用流)

      网上没有太多题解,因为这本来就是一道很简单的模型,这么简单就不想说了,这道题主要难在两个问题,一个是要保留五位有效数字,一个是关于浮点运算(后面这个东西害得我两节晚自修没了,网上也没大神说一下,第一次遇到浮点运算什么的好讨厌)。前一种我很傻很天真的方法yy然后就完了,但是很难看,下面会给出某蔡大神的空间自行过去研究他的吧。关于第二个问题,这题是求一些实数的运算,可以用两个方法,一个是直接乘,就是把原来的spfa中+号改为*号,那么相应的,建边的时候反向弧的费用就不是-asi而是1/asi,这样就会遇到一个精度问题,所有在增广时必须要把原来的dist[to]<dist[i]*edge[j].cost改为dist[i]*edge[j].cost-dist[to]>esp(esp=0.000000001)。这样程序才跑得动……第二种方法就是取对数,把*改为+,觉得神奇到不可思议,所以还是由蔡大神的题解来告诉我们这些蒟蒻吧。

    type
    
      arr=record
    
        toward,next,cap:longint;
    
        cost:double;
    
      end;
    
    var
    
      edge:array[0..1000000]of arr;
    
      dist,minc,a:array[0..100000]of double;
    
      q,first,pre,minf,b:array[0..100000]of longint;
    
      map:array[0..2000,0..2000]of double;
    
      i,j,k,l,s,t,tot,kk,maxflow,n,x:longint;
    
      chose:array[0..10000]of boolean;
    
      spent,h:double;
    
    
    function exp(x:double;y:longint):double;  //快速幂递归版!yy一下就知道为什么用快速幂了
    
    begin
    
      if y=1 then exit(x);
    
      exit(exp(x,y div 2)*exp(x,y-(y div 2)));
    
    end;
    
    
    function min(x,y:longint):longint;
    
    begin
    
      if x>y then exit(y);
    
      exit(x);
    
    end;
    
    
    procedure add(i,j,k:longint;l:double);
    
    begin
    
      edge[tot].toward:=j;
    
      edge[tot].cap:=k;
    
      edge[tot].cost:=l;
    
      edge[tot].next:=first[i];
    
      first[i]:=tot;
    
      inc(tot);
    
    end;
    
    
    procedure addedge(i,j,k:longint;l:double);
    
    begin
    
      add(i,j,k,l);
    
      add(j,i,0,1/l);
    
    end;
    
    
    function spfa:boolean;
    
    var
    
      i,head,tail,flow,j,too:longint;
    
      value,mm:double;
    
    begin
    
      fillchar(chose,sizeof(chose),false);
    
      fillchar(dist,sizeof(dist),0);
    
      dist[s]:=1;
    
      head:=1;
    
      tail:=1;
    
      q[1]:=s;
    
      mm:=0.000000001;
    
      chose[s]:=true;
    
      minf[s]:=maxlongint;
    
      while head<=tail do begin
    
        i:=q[head];
    
        j:=first[i];
    
        while j<>-1 do begin
    
          too:=edge[j].toward;
    
          value:=edge[j].cost;
    
          if (edge[j].cap>0) and (dist[i]*value-dist[too]>mm) then begin
    
            dist[too]:=dist[i]*value;
    
            pre[too]:=j;
    
            minf[too]:=min(minf[i],edge[j].cap);
    
            minc[too]:=edge[j].cost;
    
            if not chose[too] then begin
    
              chose[too]:=true;
    
              inc(tail);
    
              q[tail]:=too;
    
            end;
    
          end;
    
          j:=edge[j].next;
    
        end;
    
        inc(head);
    
        chose[i]:=false;
    
      end;
    
      if dist[t]=0 then exit(false);
    
      exit(true);
    
    end;
    
    
    procedure mcmf;
    
    var
    
      j,k,v:longint;
    
    begin
    
      spent:=1;
    
      maxflow:=0;
    
      while spfa do begin
    
        j:=minf[t];
    
        inc(maxflow,j);
    
        v:=t;
    
        while v<>s do begin
    
          spent:=spent*exp(minc[v],j);
    
          k:=pre[v];
    
          dec(edge[k].cap,j);
    
          inc(edge[k xor 1].cap,j);
    
          v:=edge[k xor 1].toward;
    
        end;
    
      end;
    
    end;
    
    
    procedure outo;
    
    var
    
      ans,i,j,k:longint;
    
    begin
    
      {writeln(spent);}
    
      spent:=spent*10;
    
      i:=1;
    
      x:=trunc(spent);
    
      while x=0 do begin
    
        spent:=spent*10;
    
        inc(i);
    
        x:=trunc(spent);
    
      end;
    
      spent:=spent/10;
    
      j:=0;
    
      while j<=5 do begin
    
        inc(j);
    
        spent:=spent*10;
    
        b[j]:=trunc(spent);
    
        spent:=spent-b[j];
    
      end;
    
      if b[6]>=5 then inc(b[5]);
    
      k:=5;
    
      while (b[k]>=10) and (k>1) do begin
    
        inc(b[k-1]);
    
        b[k]:=b[k]-10;
    
      end;
    
      if b[1]>9 then
    
        dec(i);
    
      write('0.');
    
      for k:=1 to i-1do
    
        write(0);
    
      for k:=1 to 5 do
    
        write(b[k]);
    
      readln;
    
      readln;
    
      readln;
    
    end;
    
    
    begin
    
      readln(n,kk);
    
      fillchar(map,sizeof(map),0);
    
      t:=n+2;
    
      s:=n+1;
    
      tot:=0;
    
      for i:=0 to n+3 do first[i]:=-1;
    
      for i:=1 to n do read(a[i]);
    
      for i:=1 to n do begin
    
        read(b[i]);
    
        if b[i]>0 then
    
          addedge(s,i,b[i],a[i]);
    
      end;
    
      readln;
    
      for i:=1 to n do begin
    
        read(x);
    
        if x>0 then addedge(i,t,maxlongint,1);
    
      end;
    
      readln;
    
      read(j,k);
    
      while (j<>-1) and (k<>-1) do begin
    
        readln(h,l);
    
        addedge(j,k,l,h);
    
        addedge(k,j,l,h);
    
        read(j,k);
    
      end;
    
      addedge(t,t+1,kk,1);
    
      inc(t);
    
      mcmf;
    
      if maxflow<kk then writeln('0')
    
        else outo;
    
    end.
    View Code

    vijos 1525 生命之泉 (费用流)

       这道题和志愿者招募那道题差不多,属于一个类型的,志愿者招募那道题网上可以找个很多好的题解!关于这类题简单的说就是写一些方程,然后会发现一些规律

    最核心的就是:

    一开始)P[1]=X[1]≥2

            P[2]=X[1]+X[2]≥3

            P[3]=X[2]+X[3]≥2

    可变为)

           P[1]=X[1]-Y[1]=2

           P[2]=X[1]+X[2]-Y[2]=3

           P[3]=X[2]+X[3]-Y[3]=2    (Y就是一个变量就对了)

    然后我们在最前面加一个 P[0]=0的式子,用下一个式子减上一个式子就可以得到

           P[1]-P[0]=X[1]-Y[1]=2

           P[2]-P[1]=X[2]+Y[1]-Y[2]=1

           P[3]-P[2]=-X[1]+X[3]+Y[2]-Y[3]=-1

           P[4]-P[3]=-X[2]-X[3]+Y[3]=-2

    将常数项左移,得

           P[1]-P[0]=X[1]-Y[1]-2=0

           P[2]-P[1]=X[2]+Y[1]-Y[2]-1=0

           P[3]-P[2]=-X[1]+X[3]+Y[2]-Y[3]+1=0

           P[4]-P[3]=-X[2]-X[3]+Y[3]+2=0

    我们发现一个x或y只会在两个式子里面出现,而且一个是负的,一个是正的!(大神话:很容易联想到网络流)

    对于每个x[i],从-x[i]想+x[i]连一条边(具体要根据题意),对于每个y[i]也是一样,不过y[i]和-y[i]总是出现在一前一后。

    这道题比较麻烦……要把最大费用最大流然后转为最小费用最大流跑zkw……

    type
    
      arr=record
    
        toward,cap,cost,next:longint;
    
      end;
    
    
    
    const maxn=1000000;
    
    var
    
      edge:array[0..10000]of arr;
    
      first,d,dist,q,slack:array[0..100000]of longint;
    
      chose:array[0..100000]of boolean;
    
      i,j,k,l,s,t,n,m,tot,maxcost,maxflow,kk:longint;
    
    
    
    procedure add(i,j,k,l:longint);
    
    begin
    
      edge[tot].toward:=j;
    
      edge[tot].cap:=k;
    
      edge[tot].cost:=l;
    
      edge[tot].next:=first[i];
    
      first[i]:=tot;
    
      inc(tot);
    
    end;
    
    
    
    procedure addedge(i,j,k,l:longint);
    
    begin
    
      add(i,j,k,l);
    
      add(j,i,0,-l);
    
    end;
    
    
    
    function min(x,y:longint):longint;
    
    begin
    
      if x>y then exit(y);
    
      exit(x);
    
    end;
    
    
    
    procedure spfa;
    
    var
    
      head,tail,i,too,value:longint;
    
    begin
    
      fillchar(chose,sizeof(chose),false);
    
      for i:=0 to t do d[i]:=maxlongint;
    
      head:=1;
    
      tail:=1;
    
      q[1]:=s;
    
      chose[s]:=true;
    
      d[s]:=0;
    
      while head<=tail do begin
    
        j:=q[head];
    
        i:=first[j];
    
        while i<>-1 do begin
    
          too:=edge[i].toward;
    
          value:=edge[i].cost;
    
          if (edge[i].cap>0) and (d[too]>d[j]+value) then begin
    
            d[too]:=d[j]+value;
    
            if not chose[too] then begin
    
              inc(tail);
    
              if tail=maxn then tail:=1;
    
              q[tail]:=too;
    
              chose[too]:=true;
    
            end;
    
          end;
    
          i:=edge[i].next;
    
        end;
    
        inc(head);
    
        if head=maxn then head:=1;
    
        chose[j]:=false;
    
      end;
    
    end;
    
    
    
    procedure dfs(v:longint);
    
    var
    
      i,value,too:longint;
    
    begin
    
      chose[v]:=true;
    
      i:=first[v];
    
      while i<>-1 do begin
    
        too:=edge[i].toward;
    
        value:=edge[i].cost;
    
        if (edge[i].cap>0) and (not chose[too]) and (d[too]=d[v]+value) then begin
    
          dist[too]:=dist[v]-value;
    
          dfs(too);
    
        end;
    
        i:=edge[i].next;
    
      end;
    
    end;
    
    
    
    function aug(v,flow:longint):longint;
    
    var
    
      rec,ret,too,value,i:longint;
    
    begin
    
      if v=t then begin
    
        inc(maxcost,(dist[t]-dist[s])*flow);
    
        inc(maxflow,flow);
    
        exit(flow);
    
      end;
    
      i:=first[v];
    
      chose[v]:=true;
    
      rec:=0;
    
      while i<>-1 do begin
    
        too:=edge[i].toward;
    
        value:=edge[i].cost;
    
        if (edge[i].cap>0) and (not chose[too]) then
    
          if dist[v]=dist[too]+value then begin
    
            ret:=aug(too,min(flow-rec,edge[i].cap));
    
            dec(edge[i].cap,ret);
    
            inc(edge[i xor 1].cap,ret);
    
            inc(rec,ret);
    
            if rec=flow then exit(flow);
    
          end else
    
            slack[too]:=min(slack[too],dist[too]+value-dist[v]);
    
        i:=edge[i].next;
    
      end;
    
      exit(rec);
    
    end;
    
    
    
    function rel:boolean;
    
    var
    
      spent,i:longint;
    
    begin
    
      spent:=maxlongint;
    
      for i:=0 to t do
    
        if not chose[i] then spent:=min(spent,slack[i]);
    
      if spent=maxlongint then exit(false);
    
      for i:=0 to t do
    
        if chose[i] then inc(dist[i],spent);
    
      exit(true);
    
    end;
    
    
    
    procedure costflow;
    
    begin
    
      spfa;
    
      fillchar(chose,sizeof(chose),false);
    
      fillchar(dist,sizeof(dist),0);
    
      dfs(s);
    
      repeat
    
        for i:=0 to t do slack[i]:=maxlongint;
    
        repeat
    
          fillchar(chose,sizeof(chose),false);
    
        until aug(s,maxlongint)<=0;
    
      until not rel;
    
    end;
    
    
    
    procedure into;
    
    begin
    
      readln(n,m,kk);
    
      s:=0;
    
      t:=n+2;
    
      tot:=0;
    
      for i:=0 to t do first[i]:=-1;
    
      addedge(1,t,kk,0);
    
      addedge(s,n+1,kk,0);
    
      for i:=1 to m do begin
    
        readln(j,k,l);
    
        addedge(k+1,j,1,-l);
    
      end;
    
      for i:=1 to n do
    
        addedge(i+1,i,maxlongint,0);
    
      fillchar(d,sizeof(d),0);
    
    end;
    
    
    
    begin
    
      into;
    
      costflow;
    
      writeln(maxcost);
    
      readln;
    
      readln;
    
    end.
    View Code

    vijos 1499 炸毁燃料库

       建边一直跪……为了容易想容易看,结果竟然就跪了……

       后来认真想了好久(Orz蔡大神的代码)才终于过了……线性规划

    一开始

       x[1]+x[2]+x[3]+...+x[m]   <=k;

       x[2]+x[3]+x[4]+...+x[m+1] <=k;

       x[3]+x[4]+x[5]+...+x[m+2] <=k;

       ......

       x[n-m+1]+...+x[n]         <=k;

    转换为

                                       0=0

       x[1]+x[2]+x[3]+...+x[m]   -y[1]-k=0;

       x[2]+x[3]+x[4]+...+x[m+1] -y[2]-k=0;

       x[3]+x[4]+x[5]+...+x[m+2] -y[3]-k=0;

       ...

       x[n-m+1]+...+x[n] -y[n-m+1]-k=0;

    下面减上面

      

    1   x[1]+x[2]+x[3]+...+x[m]  -y[1]-k=0

    2   x[m+1]  -x[1]          +y[1]-y[2] =0;

    3   x[m+2]  -x[2]          +y[2]-y[3] =0;

    4   x[m+3]  -x[3]          +y[3]-y[4] =0;

       ......

    (    x[m+m]  -x[m]          +y[m]-y[m+1]=0

        x[m+m+1]-x[m+1]             )

       ......

    n-m+1   x[n]    -x[n-m]        +y[n-m]-y[n-m+1]=0;

    n-m+2  -x[n-m+1]-x[n-m]...-x[n]+y[n-m+1]+k=0

    然后就是中间那种情况会导致图有两种结果,判断条件是m≥n-m 是的话就是第一种图(没有括号那种情况),不是的话就是(有括号的图)

    type
    
      arr=record
    
        toward,next,cap,cost:longint;
    
      end;
    
    const
    
      mm=1000000;
    
    var
    
      edge:array[0..100000]of arr;
    
      first,dist,d,q,slack,a:array[0..mm]of longint;
    
      i,j,k,l,n,m,s,t,tot,maxcost,maxflow,kk:longint;
    
      chose:array[0..mm]of boolean;
    
    
    
    procedure add(i,j,k,l:longint);
    
    begin
    
      edge[tot].toward:=j;
    
      edge[tot].cap:=k;
    
      edge[tot].cost:=l;
    
      edge[tot].next:=first[i];
    
      first[i]:=tot;
    
      inc(tot);
    
    end;
    
    
    
    procedure addedge(i,j,k,l:longint);
    
    begin
    
      add(i,j,k,l);
    
      add(j,i,0,-l);
    
    end;
    
    
    
    function min(x,y:longint):longint;
    
    begin
    
      if x>y then exit(y);
    
      exit(x);
    
    end;
    
    
    
    procedure spfa;
    
    var
    
      head,tail,i,too,value:longint;
    
    begin
    
      fillchar(chose,sizeof(chose),false);
    
      for i:=0 to t do d[i]:=maxlongint;
    
      head:=1;
    
      tail:=1;
    
      q[1]:=s;
    
      chose[s]:=true;
    
      d[s]:=0;
    
      while head<=tail do begin
    
        j:=q[head];
    
        i:=first[j];
    
        while i<>-1 do begin
    
          too:=edge[i].toward;
    
          value:=edge[i].cost;
    
          if (edge[i].cap>0) and (d[too]>d[j]+value) then begin
    
            d[too]:=d[j]+value;
    
            if not chose[too] then begin
    
              inc(tail);
    
              if tail=mm then tail:=1;
    
              q[tail]:=too;
    
              chose[too]:=true;
    
            end;
    
          end;
    
          i:=edge[i].next;
    
        end;
    
        inc(head);
    
        if head=mm then head:=1;
    
        chose[j]:=false;
    
      end;
    
    end;
    
    
    
    procedure dfs(v:longint);
    
    var
    
      i,value,too:longint;
    
    begin
    
      chose[v]:=true;
    
      i:=first[v];
    
      while i<>-1 do begin
    
        too:=edge[i].toward;
    
        value:=edge[i].cost;
    
        if (edge[i].cap>0)  and (d[too]=d[v]+value) then begin
    
          dist[too]:=dist[v]-value;
    
          dfs(too);
    
        end;
    
        i:=edge[i].next;
    
      end;
    
    end;
    
    
    
    
    
    function aug(v,flow:longint):longint;
    
    var
    
      rec,ret,i,too,value:longint;
    
    begin
    
      if v=t then begin
    
        inc(maxcost,(dist[t]-dist[s])*flow);
    
        inc(maxflow,flow);
    
        exit(flow);
    
      end;
    
      rec:=0;
    
      chose[v]:=true;
    
      i:=first[v];
    
      while i<>-1 do begin
    
        too:=edge[i].toward;
    
        value:=edge[i].cost;
    
        if (edge[i].cap>0) and (not chose[too]) then
    
          if dist[v]=dist[too]+value then begin
    
            ret:=aug(too,min(flow-rec,edge[i].cap));
    
            dec(edge[i].cap,ret);
    
            inc(edge[i xor 1].cap,ret);
    
            inc(rec,ret);
    
            if rec=flow then exit(flow);
    
          end else
    
            slack[too]:=min(slack[too],dist[too]+value-dist[v]);
    
        i:=edge[i].next;
    
      end;
    
      exit(rec);
    
    end;
    
    
    
    function rel:boolean;
    
    var
    
      spent,i:longint;
    
    begin
    
      spent:=maxlongint;
    
      for i:=0 to t do
    
        if not chose[i] then spent:=min(spent,slack[i]);
    
      if spent=maxlongint then exit(false);
    
      for i:=0 to t do
    
        if chose[i] then inc(dist[i],spent);
    
      exit(true);
    
    end;
    
    
    
    procedure maxc;
    
    begin
    
      spfa;
    
      fillchar(chose,sizeof(chose),false);
    
      fillchar(dist,sizeof(dist),0);
    
      dfs(s);
    
      repeat
    
        for i:=0 to t do slack[i]:=maxlongint;
    
        repeat
    
          fillchar(chose,sizeof(chose),false);
    
        until aug(s,maxlongint)<=0;
    
      until not rel;
    
    end;
    
    
    
    procedure into;
    
    begin
    
      readln(n,m,kk);
    
      s:=0;
    
      t:=n-m+3;
    
      for i:=0 to t do first[i]:=-1;
    
      tot:=0;
    
      for i:=1 to n do
    
        read(a[i]);
    
      addedge(s,n-m+2,kk,0);
    
      addedge(1,t,kk,0);
    
      if m>=n-m then begin
    
        for i:=1 to n-m do
    
          addedge(i+1,1,1,-a[i]);
    
        for i:=n-m+1 to m do
    
          addedge(n-m+2,1,1,-a[i]);
    
        for i:=m+1 to n do
    
          addedge(n-m+2,i-m+1,1,-a[i]);
    
      end else begin
    
        for i:=1 to m do
    
          addedge(i+1,1,1,-a[i]);
    
        for i:=m+1 to n-m do
    
          addedge(i+1,i-m+1,1,-a[i]);
    
        for i:=n-m+1 to n do
    
          addedge(n-m+2,i-m+1,1,-a[i]);
    
      end;
    
      for i:=1 to n-m+1 do
    
        addedge(i+1,i,maxlongint,0);
    
      fillchar(d,sizeof(d),0);
    
    end;
    
    
    
    begin
    
      into;
    
      maxc;
    
      writeln(maxcost);
    
    end.
    View Code

    vijos 1734 海拔 (网络流转为最短路)

       orz这题特别神奇,作为蒟蒻完全被考倒了。

       找了网上的题解最好的就是这个了http://blog.sina.com.cn/s/blog_86942b1401014ajk.html (其实有另一个……但是莫名挂了,orz)。

       这题很容易想到一个最小割模型,但是会tle!所以只能转为对偶图,这个神奇的东西推荐去看集训队论文:周冬《两极相通——浅析最大—最小定理在信息学竞赛中的应用》。讲的很详细!

       然后就是spfa,裸的spfa不能过,所以要加lll+slt优化!

       或者是二叉堆优化的dij……

       然后这题由于信息量太大就跪了很久……先搞懂一系列概念,然后就是略蛋疼的spfa了,在tle无数次后终于把spfa改的能过最后一个点(一直卡最后一个点orz)……

    //spfa版  
    
    type
    
      arr=record
    
        toward,next,cost:longint;
    
      end;
    
    const
    
      mm=300000;
    
    var
    
      edge:array[0..5*mm]of arr;
    
      first,d,q:array[0..mm]of longint;
    
      map:array[0..2000,0..2000]of longint;
    
      f:array[0..mm]of boolean;
    
      i,j,k,l,n,m,tot,s,t,sum:longint;
    
    
    
    procedure addedge(i,j,k:longint);
    
    begin
    
      inc(tot);
    
      edge[tot].toward:=j;
    
      edge[tot].next:=first[i];
    
      first[i]:=tot;
    
      edge[tot].cost:=k;
    
    end;
    
    
    
    procedure spfa(v:longint);
    
    var
    
      head,tail,i,too,j,value,len,k:longint;
    
      sum:int64;
    
    begin
    
      sum:=0;
    
      len:=1;
    
      fillchar(f,sizeof(f),false);
    
      fillchar(d,sizeof(d),$7f);
    
      d[v]:=0;
    
      head:=0;
    
      tail:=1;
    
      q[1]:=v;
    
      f[v]:=true;
    
      while head<>tail do begin
    
        inc(head);
    
        if head>mm then head:=1;
    
        while d[q[head]]>sum div len do begin  //lll优化,记得sum要int64!因为这个跪了一节晚自修!
    
          inc(tail);
    
          if tail>mm then tail:=1;
    
          q[tail]:=q[head];
    
          inc(head);
    
          if head>mm then head:=1;
    
        end;
    
        j:=q[head];
    
        i:=first[j];
    
        dec(len);
    
        dec(sum,d[j]);
    
        while i<>-1 do begin
    
          value:=edge[i].cost;
    
          too:=edge[i].toward;
    
          if (d[j]+value<d[too]) then begin
    
            d[too]:=d[j]+value;
    
            if (not f[too]) and (d[too]<d[t])then begin  //d[too]<d[t] 这步很神奇!
    
              inc(len);
    
              inc(sum,d[too]);
    
              k:=head+1;
    
              if k>mm then k:=1;
    
              if d[too]<d[q[k]] then begin    //slf优化
    
                f[too]:=true;
    
                q[head]:=too;
    
                head:=head-1;
    
                if head<1 then head:=mm;
    
              end else begin
    
                f[too]:=true;
    
                inc(tail);
    
                if tail>mm then tail:=1;
    
                q[tail]:=too;
    
              end;
    
            end;
    
          end;
    
          i:=edge[i].next;
    
        end;
    
        f[j]:=false;
    
      end;
    
    end;
    
    
    
    procedure into;
    
    begin
    
      s:=0;
    
      t:=n*n+1;
    
      sum:=0;
    
      tot:=0;
    
      for i:=0 to n do
    
        map[0,i]:=t;
    
      for i:=0 to n do
    
        map[i,n+1]:=t;
    
      for i:=0 to n do
    
        map[i,0]:=s;
    
      for i:=0 to n do
    
        map[n+1,i]:=s;
    
      for i:=1 to n do
    
        for j:=1 to n do begin
    
          inc(sum);
    
          map[i,j]:=sum;
    
        end;
    
    
    
      for i:=1 to n+1 do
    
        for j:=1 to n do begin
    
          read(k);
    
          addedge(map[i,j],map[i-1,j],k);
    
        end;
    
    
    
      for i:=1 to n do
    
        for j:=1 to n+1 do begin
    
          read(k);
    
          addedge(map[i,j-1],map[i,j],k);
    
        end;
    
    
    
      for i:=1 to n+1 do
    
        for j:=1 to n do begin
    
          read(k);
    
          addedge(map[i-1,j],map[i,j],k);
    
        end;
    
    
    
      for i:=1 to n do
    
        for j:=1 to n+1 do begin
    
          read(k);
    
          addedge(map[i,j],map[i,j-1],k);
    
        end;
    
    end;
    
    
    
    procedure outo;
    
    begin
    
      readln(n);
    
      for i:=0 to n*n+2 do first[i]:=-1;
    
    end;
    
    
    
    begin
    
      outo;
    
      into;
    
      spfa(s);
    
      writeln(d[t]);
    
    end.
    
    
    
    //据说这题dij快,然后就写了下,果然快了很多&……
    
    type
    
      arr=record
    
        toward,next,cost:longint;
    
      end;
    
      ar=record
    
        value,toward:longint;
    
      end;
    
    const
    
      mm=300000;
    
    var
    
      edge:array[0..5*mm]of arr;
    
      first,g:array[0..mm]of longint;
    
      head:array[0..5*mm]of ar;
    
      map:array[0..2000,0..2000]of longint;
    
      f:array[0..mm]of boolean;
    
      i,j,k,l,n,m,tot,s,t,sum,len:longint;
    
    
    
    procedure addedge(i,j,k:longint);
    
    begin
    
      inc(tot);
    
      edge[tot].toward:=j;
    
      edge[tot].next:=g[i];
    
      g[i]:=tot;
    
      edge[tot].cost:=k;
    
    end;
    
    
    
    procedure into;
    
    begin  
    
      readln(n);
    
      for i:=0 to n*n+2 do g[i]:=-1;
    
      s:=n*n+1;
    
      t:=n*n+2;
    
      sum:=0;
    
      tot:=0;
    
      for i:=0 to n do
    
        map[0,i]:=t;
    
      for i:=0 to n do
    
        map[i,n+1]:=t;
    
      for i:=0 to n do
    
        map[i,0]:=s;
    
      for i:=0 to n do
    
        map[n+1,i]:=s;
    
      for i:=1 to n do
    
        for j:=1 to n do begin
    
          inc(sum);
    
          map[i,j]:=sum;
    
        end;
    
      for i:=1 to n+1 do
    
        for j:=1 to n do begin
    
          read(k);
    
          addedge(map[i,j],map[i-1,j],k);
    
        end;
    
    
    
      for i:=1 to n do
    
        for j:=1 to n+1 do begin
    
          read(k);
    
          addedge(map[i,j-1],map[i,j],k);
    
        end;
    
    
    
      for i:=1 to n+1 do
    
        for j:=1 to n do begin
    
          read(k);
    
          addedge(map[i-1,j],map[i,j],k);
    
        end;
    
    
    
      for i:=1 to n do
    
        for j:=1 to n+1 do begin
    
          read(k);
    
          addedge(map[i,j],map[i,j-1],k);
    
        end;
    
    end;
    
    
    
    procedure swap(a,b:longint);
    
    var
    
      j:ar;
    
    begin
    
      j:=head[a];
    
      head[a]:=head[b];
    
      head[b]:=j;
    
      first[head[a].toward]:=a;
    
      first[head[b].toward]:=b;
    
    end;
    
    
    
    procedure decre(i:longint);
    
    begin
    
      while (i<>1) and (head[i].value<head[i shr 1].value) do begin
    
        swap(i,i shr 1);
    
        i:=i shr 1;
    
      end;
    
    end;
    
    
    
    procedure headpify;
    
    var
    
      i:longint;
    
    begin
    
      i:=2;
    
      while i<=len do begin
    
        if (i<len) and (head[i+1].value<head[i].value) then inc(i);
    
        if head[i].value<head[i shr 1].value then begin
    
          swap(i,i shr 1);
    
          i:=i*2;
    
        end
    
          else break;
    
      end;
    
    end;
    
    
    
    procedure relax(i,j,k:longint);
    
    begin
    
      if k+head[first[i]].value<head[first[j]].value then begin
    
        head[first[j]].value:=k+head[first[i]].value;
    
        decre(first[j]);
    
      end;
    
    end;
    
    
    
    procedure dij;
    
    var
    
      i,too,va:longint;
    
    begin
    
      for i:=1 to t do begin
    
        head[i].toward:=i;
    
        head[i].value:=maxlongint;
    
        first[i]:=i;
    
      end;
    
      head[s].value:=0;
    
      swap(1,s);
    
      len:=t;
    
      while len>0 do begin
    
        i:=head[1].toward;
    
        if i=t then exit;
    
        swap(1,len);
    
        dec(len);
    
        headpify;
    
        j:=g[i];
    
        while j<>-1 do begin
    
          too:=edge[j].toward;
    
          va:=edge[j].cost;
    
          if first[too]<=len then relax(i,too,va);
    
          j:=edge[j].next;
    
        end;
    
      end;
    
    end;
    
    
    
    begin
    
      into;
    
      dij;
    
      writeln(head[1].value);
    
    end.
    View Code
  • 相关阅读:
    Vmware克隆虚拟机后网卡eth0变eth1解决
    iptables详解
    Python小白的发展之路之Python基础(二)【字符串、列表、集合、文件操作】
    ubuntu下的apt-get内网本地源的搭建
    Python小白的发展之路之Python基础(一)
    qtp录制---点击Activescreen时提示“一个或多个ActiveX控件无法显示”
    qtp录制ie,提示“是否只查看安全传送的网页内容”
    qtp录制ie崩溃
    bug的记录方式
    测试计划和测试方案的区别
  • 原文地址:https://www.cnblogs.com/Macaulish/p/6492057.html
Copyright © 2011-2022 走看看