USACO 4.4.2 Pollutant Control 最小边割集

来源:互联网 发布:桃源网络硬盘 编辑:程序博客网 时间:2024/05/22 19:59

 这题一看就是最小割的网络流,于是乎转化为最大流。但是麻烦的是,同时还要处理最小的边数以及字典序最小的输出。这可怎么办啊?网上的各种办法都是把边权*1001+1等等。但是我仍然就得这种方法有待商榷。

        在网上查了一下,得到了正解。我们先求出最小割,然后把边权从大到小排序。(这样的话,割的边数会更少)每次枚举一条边,模拟删掉这条边并再求最小割。如果最小割减少的量等于这条边的边权,说明这条边在最小割的集合里。然后真的删除这条边,继续处理。最后输出删除的边数即可。

        最后提醒一下:从x到y可以有很多条不同的路,所以在删边时不能直接赋成0,而是减掉这条边的边权。

代码:

{ID: ymwbegi1PROG: milk6LANG: PASCAL}var  n,m,ans,tot,s,i:longint;  c,c1:array[1..32,1..32] of longint;  fa:array[1..32] of longint;  v:array[1..1000] of boolean;  side:array[0..1000,1..4] of longint;procedure init;var  i,x,y,z:longint;begin  readln(n,m);  for i:=1 to m do  begin    readln(x,y,z);    inc(c[x,y],z);    inc(c1[x,y],z);    side[i,1]:=x;    side[i,2]:=y;    side[i,3]:=z;    side[i,4]:=i;  end;end;function find(x:longint):boolean;var  i:longint;begin  if x=n then exit(true);  for i:=1 to n do    if (fa[i]=-1)and(c[x,i]>0) then    begin      fa[i]:=x;      if find(i) then exit(true);    end;  find:=false;end;procedure add;var  i,min:longint;begin  min:=maxlongint;  i:=n;  while i>1 do  begin    if c[fa[i],i]<min then min:=c[fa[i],i];    i:=fa[i];  end;  i:=n;  ans:=ans+min;  while i>1 do  begin    dec(c[fa[i],i],min);    inc(c[i,fa[i]],min);    i:=fa[i];  end;end;procedure main;var  i:longint;begin  for i:=2 to n do    fa[i]:=-1;  fa[1]:=0;  while find(1) do  begin    add;    for i:=2 to n do      fa[i]:=-1;    fa[1]:=0;  end;end;procedure sort;var  i,j:longint;begin  for i:=1 to m-1 do    for j:=i+1 to m do      if (side[i,3]<side[j,3])or(side[i,3]=side[j,3])and(side[i,4]>side[j,4]) then      begin        side[0]:=side[i];side[i]:=side[j];side[j]:=side[0];      end;end;begin  assign(input,'milk6.in');  assign(output,'milk6.out');  reset(input);  rewrite(output);  init;  main;  write(ans,' ');  sort;  tot:=ans;  fillchar(v,sizeof(v),false);  for i:=1 to m do  begin    ans:=0;    c:=c1;    dec(c[side[i,1],side[i,2]],side[i,3]);    main;    if tot-ans=side[i,3] then    begin      inc(s);      v[side[i,4]]:=true;      dec(c1[side[i,1],side[i,2]],side[i,3]);      tot:=ans;    end else inc(c[side[i,1],side[i,2]],side[i,3]);  end;  writeln(s);  s:=0;  for i:=1 to m do    if v[i] then writeln(i);  close(input);  close(output);end.


0 0