[BZOJ2502]清理雪道 有上下界的最小流

今天刚学的上下界网络流,概念都还不是很熟。。。
题意立即可以转化成每条边流量下界为1,上界为inf,s向每个点连边,每个点向t连边,下界都为0,上界都为inf,求最小流量。
于是建立超级源和超级汇,按套路先求出一个可行流,记ans1为可行流中t->s这条边的流量。然后删除t->s,再跑一个t到s的最大流(退一些流使总流量变小),记ans2为这次最大流的流量,答案即为ans1-ans2。
要注意ans1不是可行流的总流量,而是s->t的流量,我就这样WA了一发。。。
代码:

type
  edge=^edgenode;
  edgenode=record
    t,c,f:longint;
    next,rev:edge;
  end;
const maxl=1000000000;
var
  n,i,j,x,z,s,t,ss,tt,nows,nowt,ans1,ans2,tot:longint;
  ind:array[0..110]of longint;
  con:array[0..200]of edge;
  ne,dl:array[0..200]of longint;
  visit:array[0..200]of boolean;
procedure ins(x,y,z:longint);
var
  p:edge;
begin
  new(p);
  p^.t:=y;
  p^.c:=z;
  p^.f:=0;
  p^.next:=con[x];
  con[x]:=p;
  new(p);
  p^.t:=x;
  p^.c:=0;
  p^.f:=0;
  p^.next:=con[y];
  con[y]:=p;
  con[x]^.rev:=con[y];
  con[y]^.rev:=con[x];
end;
function min(x,y:longint):longint;
begin
  if x>y then exit(y)
  else exit(x);
end;
function bfs:boolean;
var
  p:edge;
  head,tail,x:longint;
begin
  head:=1;
  tail:=1;
  dl[1]:=nows;
  ne[nows]:=1;
  bfs:=false;
  while head<=tail do
  begin
    x:=dl[head];
    //writeln(x);
    if x=nowt then bfs:=true;
    p:=con[x];
    while p<>nil do
    begin
      if (ne[p^.t]=0)and(p^.c>p^.f) then
      begin
        ne[p^.t]:=ne[x]+1;
        inc(tail);
        dl[tail]:=p^.t;
      end;
      p:=p^.next;
    end;
    inc(head);
  end;
end;
function dinic(k,flow:longint):longint;
var
  p:edge;
  o:longint;
begin
  if k=nowt then exit(flow);
  if visit[k]=true then exit(0);
  p:=con[k];
  dinic:=0;
  o:=0;
  while p<>nil do
  begin
    if (ne[p^.t]=ne[k]+1)and(p^.c>p^.f) then
    begin
      o:=dinic(p^.t,min(flow-dinic,p^.c-p^.f));
      inc(dinic,o);
      inc(p^.f,o);
      dec(p^.rev^.f,o);
      if dinic=flow then break;
    end;
    p:=p^.next;
  end;
  if dinic=0 then visit[k]:=true;
end;

function work():longint;
begin
  fillchar(ne,sizeof(ne),0);
  work:=0;
  while bfs do
  begin
    fillchar(visit,sizeof(visit),false);
    work:=work+dinic(nows,maxl);
    fillchar(ne,sizeof(ne),0);
  end;
end;
begin
  readln(n);
  s:=0;t:=n+1;ss:=n+2;tt:=n+3;
  fillchar(ind,sizeof(ind),0);
  for i:=1 to n do
  begin
    read(x);
    dec(ind[i],x);
    for j:=1 to x do
    begin
      read(z);
      inc(ind[z]);
      ins(i,z,maxl);
    end;
    ins(s,i,maxl);
    ins(i,t,maxl);
  end;
  ins(t,s,maxl);
  for i:=1 to n do
  if ind[i]>0 then ins(ss,i,ind[i])
  else ins(i,tt,-ind[i]);
  nows:=ss;
  nowt:=tt;
  work;
  ans1:=con[t]^.f;
  con[t]:=con[t]^.next;
  nows:=t;
  nowt:=s;
  ans2:=work;
  writeln(ans1-ans2);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值