您的位置:首页 > 其它

bzoj1834 最大流+最小费用最大流

2015-04-15 23:57 183 查看
就当模板啦…

不过这题第二问的构图还是可以想一下的。。。

在残量网络中把原来的边全部加一遍,但是有费用w,容量无限大,一开始的边还是费用为0

新建一个源点s,s向1连一条边,容量为k,费用为0,保证这条边满流,就有最小费用了。

[code]program bzoj1834;
type point=record
        s,t,cap,flow,o,w,next:longint;
end;
var p,l,n,m,k,c,i:longint;
      v1:array[0..1010]of boolean;
      edge:array[1..30010]of point;
      head,d:array[0..1010]of longint;
      b:array[1..10000000]of longint;
      u,v,w:array[0..5010]of longint;
procedure add(u,v,c,w:longint);
begin
 l:=l+1;
 edge[l].s:=u;
 edge[l].t:=v;
 edge[l].cap:=c;
 edge[l].flow:=0;
 edge[l].o:=l+1;
 edge[l].w:=w;//费用
 edge[l].next:=head[u];
 head[u]:=l;
 l:=l+1;
 edge[l].s:=v;
 edge[l].t:=u;
 edge[l].cap:=c;
 edge[l].flow:=c;
 edge[l].o:=l-1;
 edge[l].w:=-w;
 edge[l].next:=head[v];
 head[v]:=l;
end;
function min(a,b:longint):longint;
begin
 if a<b then min:=a else min:=b;
end;

function bfs:boolean;
var top,tail,p:longint;
begin
 d[1]:=1;
 top:=1;tail:=1;
 b[1]:=1;
 fillchar(v1,sizeof(v1),false);
 v1[1]:=true;
 repeat
  p:=head[b[top]];
  while p<>-1 do
       begin
         if (v1[edge[p].t]=false)and(edge[p].cap>edge[p].flow) then
              begin
               v1[edge[p].t]:=true;
               d[edge[p].t]:=d[b[top]]+1;//层次
               tail:=tail+1;
               b[tail]:=edge[p].t;
              end;
         p:=edge[p].next;
       end;
  top:=top+1;
 until top>tail;
 exit(v1
);
end;

function addflow(x,maxflow:longint):longint;
var p,o:longint;
begin
  if (x=n) or (maxflow=0) then exit(maxflow);
  addflow:=0;//这个一定要写!!
  p:=head[x];
  while p<>-1 do
       begin
         if (d[edge[p].t]=d[x]+1)and(edge[p].cap>edge[p].flow) then
          begin
            o:=addflow(edge[p].t,min(maxflow,edge[p].cap-edge[p].flow));
            if o>0 then
             begin
               inc(edge[p].flow,o);
               dec(edge[edge[p].o].flow,o);
               maxflow:=maxflow-o;
               addflow:=addflow+o;
               if maxflow=0 then break;
             end;
          end;
         p:=edge[p].next;
       end;
end;

function dinic:longint;
begin
 dinic:=0;
 while bfs do
      dinic:=dinic+addflow(1,maxlongint);
end;

function spfa:longint;
var cost,top,tail,i,p:longint;
      pre,re:array[0..1010]of longint;
      flag:array[0..1010]of boolean;
      d:array[0..1010]of longint;
      mm:longint;
begin
 cost:=0;
 while true do
    begin
      top:=1;tail:=1;
      b[1]:=0;
      for i:=0 to n do d[i]:=maxlongint;
      d[0]:=0;//流量
      fillchar(pre,sizeof(pre),0);
      pre[0]:=-1;
      fillchar(re,sizeof(re),0);
      fillchar(flag,sizeof(flag),true);
      flag[0]:=false;
      repeat
       p:=head[b[top]];
       while p<>-1 do
         begin
          if (edge[p].cap>edge[p].flow)and(d[b[top]]+edge[p].w<d[edge[p].t]) then
            begin
             d[edge[p].t]:=d[b[top]]+edge[p].w;
             pre[edge[p].t]:=b[top];
             re[edge[p].t]:=p;
             if flag[edge[p].t] then
              begin
                flag[edge[p].t]:=false;
                tail:=tail+1;
                b[tail]:=edge[p].t;
              end;
            end;
          p:=edge[p].next;
         end;
        flag[b[top]]:=true;
        top:=top+1;
      until top>tail;
      if d
=maxlongint then break;
      i:=n;
      mm:=maxlongint;
      while pre[i]<>-1 do
        begin
          mm:=min(mm,edge[re[i]].cap-edge[re[i]].flow);
          i:=pre[i];
        end;
      i:=n;
      while pre[i]<>-1 do
        begin
         inc(edge[re[i]].flow,mm);
         dec(edge[edge[re[i]].o].flow,mm);
         cost:=cost+mm*edge[re[i]].w;
         i:=pre[i];
        end;
    end;
  spfa:=cost;
end;
begin
 read(n,m,k);
 for i:=0 to n do head[i]:=-1;
 for i:=1 to m do
     begin
       read(u[i],v[i],c,w[i]);
       add(u[i],v[i],c,0);
     end;
 write(dinic,' ');
 //最小费用最大流
 for i:=1 to m do
    add(u[i],v[i],maxlongint,w[i]);
 add(0,1,k,0);

 writeln(spfa);
 readln;readln;
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: