容量有上下界的可行流

【分析】把每行和每列看成一个点,然后先建一个源S和汇T,行就与S连,边的上下界均为要求的和,列就
与T连,上下界也是和,根据限制条件,调整行与列之间的关系。然后图就建好一半了。然后就是
求这个有上下界的网络的可行流
amber的《图论总结》里也写到怎么求
【复杂度】O(Maxflow)
【小结】 这题模型有点难想,但是建图十分麻烦。然后我的程序一直不能AC,我很郁闷,不知道为什么,
先贴一下,如果有人知道的话联系我

type ok=record
     x,y,nt:longint;
     end;
var tc,n,m,st,en,ptot,tot,sum:longint;
    e:Array[1..100000]of ok;
    head,cur,stack,d,inflow,outflow:array[0..500]of longint;
    map,minm,maxm:array[0..500,0..500]of longint;
    flag:boolean;
procedure add(a,b,c:longint);
begin
  inc(tot);
  e[tot].x:=a;e[tot].y:=b;
  e[tot].nt:=head[a];head[a]:=tot;
  map[a,b]:=c;
  inc(tot);
  e[tot].x:=b;e[tot].y:=a;
  e[tot].nt:=head[b];head[b]:=tot;
end;
procedure change(x,y,z:longint;ch:char);
begin
  if ch='=' then begin minm[x,y]:=z;maxm[x,y]:=z;end;
  if ch='>' then begin if z>=minm[x,y] then minm[x,y]:=z+1;end;
  if ch='<' then begin if z<=maxm[x,y] then maxm[x,y]:=z-1;end;
  if minm[x,y]>maxm[x,y] then flag:=true;
end;
procedure fill;
var i,j:longint;
begin
  fillchar(outflow,sizeof(outflow),0);
  fillchar(inflow,sizeof(inflow),0);
  fillchar(head,sizeof(head),0);
  fillchar(map,sizeof(map),0);
  for i:=0 to 500 do
    for j:=0 to 500 do
      begin
      minm[i,j]:=0;maxm[i,j]:=1001;
      end;
  st:=0;en:=n+m+1;tot:=0;flag:=false;sum:=0;
end;
function bfs:boolean;
var i,t,k,k1,now:longint;
begin
  for i:=0 to en do d[i]:=-1;
  stack[1]:=st;d[st]:=0;
  k:=0;k1:=1;
  while k<k1 do
    begin
    inc(k);now:=stack[k];
    t:=head[now];cur[now]:=t;
    while t<>0 do
      begin
      if (map[e[t].x,e[t].y]>0)and(d[e[t].y]=-1) then
        begin
        inc(k1);stack[k1]:=e[t].y;
        d[e[t].y]:=d[now]+1;
        end;
      t:=e[t].nt;
      end;
    end;
  if d[en]=-1 then exit(false) else exit(true);
end;
function dinic(now,tot:longint):longint;
var s,temp,flow:longint;
begin
  if now=en then exit(tot);
  s:=0;
  while cur[now]<>0 do
    begin
    if (map[now,e[cur[now]].y]>0)and(d[e[cur[now]].y]=d[now]+1) then
      begin
      temp:=tot;if map[now,e[cur[now]].y]<temp then temp:=map[now,e[cur[now]].y];
      flow:=dinic(e[cur[now]].y,temp);
      inc(s,flow);
      dec(tot,flow);
      dec(map[now,e[cur[now]].y],flow);
      inc(map[e[cur[now]].y,now],flow);
      if tot=0 then break;
      end;
    cur[now]:=e[cur[now]].nt;
    end;
  exit(s);
end;
procedure print;
var i,j:longint;
begin
  for i:=1 to n do
    begin
    for j:=1 to m do
      begin
      write(map[j+n,i]+minm[i,j+n]);
      if j<m then write(' ');
      end;
    writeln;
    end;
end;
procedure work;
var ans,i,j:longint;
begin
  ans:=0;
  while bfs do ans:=ans+dinic(st,maxlongint);
  {writeln(ans);
  for i:=0 to n+m+3 do
      begin
      for j:=0 to m+n+3 do write(map[i,j],' ');
      writeln;
      end;writeln;}
  if ans<>sum div 2 then begin writeln('IMPOSSIBLE');exit;end;
  st:=0;en:=n+m+1;
  for i:=ptot+1 to tot do
    begin
    map[e[i].x,e[i].y]:=0;//head[e[i].x]:=e[i].nt;
    end;
  ans:=0;
  while bfs do ans:=ans+dinic(st,maxlongint);
  print;
end;
procedure main;
var lim,tt,i,j,k,x,y,z:longint;
    ch,tch:char;
begin
  readln(tc);
  for tt:=1 to tc do
    begin
    if tt>1 then writeln;
    //writeln(tc-tt+1);
    readln;readln(n,m);
    //fillchar
    fill;
    for i:=1 to n do begin read(x);minm[st,i]:=x;;maxm[st,i]:=x;end;readln;
    for i:=1 to m do begin read(x);minm[i+n,en]:=x;;maxm[i+n,en]:=x;end;readln;
    readln(lim);
    for i:=1 to lim do
      begin
      read(x,y,tch,ch,tch,z);
      if (x=0)and(y=0) then
        begin
        for j:=1 to n do
          for k:=1 to m do
            change(j,k+n,z,ch);
        continue;
        end;
      if x=0 then for j:=1 to n do change(j,y+n,z,ch);
      if y=0 then for j:=1 to m do change(x,j+n,z,ch);
      if (x<>0)and(y<>0) then change(x,y+n,z,ch);
      end;
    if flag then begin writeln('IMPOSSIBLE');continue;end;
    //set up graph
    for i:=1 to n do
      begin
      inc(outflow[st],minm[st,i]);inc(inflow[i],minm[st,i]);
      add(st,i,maxm[st,i]-minm[st,i]);//add(i,st,0,-1);
      end;
    for i:=1 to m do
      begin
      inc(outflow[i+n],minm[i+n,en]);inc(inflow[en],minm[i+n,en]);
      add(i+n,en,maxm[i+n,en]-minm[i+n,en]);//add(en,i+n,0,-1);
      end;
    for i:=1 to n do
      for j:=1 to m do
        begin
        inc(outflow[i],minm[i,j+n]);inc(inflow[j+n],minm[i,j+n]);
        add(i,j+n,maxm[i,j+n]-minm[i,j+n]);//add(j+n,i,0,-1);
        end;
    st:=n+m+2;en:=n+m+3;ptot:=tot;
    for i:=0 to n+m+1 do
      begin
      inc(sum,inflow[i]);inc(sum,outflow[i]);
      add(st,i,inflow[i]);//add(i,st,0,-1);
      add(i,en,outflow[i]);//add(en,i,0,-1);
      end;
    add(n+m+1,0,99999999);//add(0,n+m+1,0,-1);
    {writeln(sum);
    for i:=0 to n+m+1 do
      begin
      for j:=0 to m+n+1 do write(minm[i,j],' ');
      writeln;
      end;writeln;
        for i:=0 to n+m+1 do
      begin
      for j:=0 to m+n+1 do write(maxm[i,j],' ');
      writeln;
      end;writeln;
    for i:=0 to n+m+3 do
      begin
      for j:=0 to m+n+3 do write(map[i,j],' ');
      writeln;
      end;}
    work;

    end;
end;
begin
  assign(input,'1.in');
  reset(input);
  assign(output,'1.out');
  rewrite(output);
  main;
  close(input);
  close(output);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值