USACO 4.4.2 Pollutant Control 最小边割集

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

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

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

代码:

{
ID: ymwbegi1
PROG: milk6
LANG: 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.


你可能感兴趣的:(USACO 4.4.2 Pollutant Control 最小边割集)