Alice 和 Bob在图论课程上学习了最大流和 最小费用流的相关知识。
最大流问题 :给定一张有向图 表示运输网络 ,一个源点S和一个汇点T,每条边都有最大流量。 一个合法的网络流方案必须满足: (1) 每条边的 实际流量都不超过其最大流量且非负 ;(2) 除了源点 S和汇点 T之外,对于其余所有点都满足该点总流入量 等于总流出量;而 S点的净流出量等于 T点的净流入量,这个值也即该网络流方案的总运输量。 最大流问题就是对于给定的运输网络,求总运输量最大的网络流方案。
上图 表示 了一个 最大流问题。 对于每条边 ,右边的数代表该边的最大流量, 左边的数代表在最优解中,该边的实际流量。需要注意到 ,一个最大流问题的解可能不是唯一的。
对于一张给定的 运输网络 ,Alice 先确定一个最大流 ,如果有多种解, Alice 可以任选一种; 之后 Bob在每条边上分配单位花费 (单位花费必须是非负实数), 要求所有边的单位花费之和等于 P。总费用等于每一条边 的实际流量乘以该边的单位花费。 需要注意到, Bob在分配单位花费之前,已经知道Alice 所给出的最大流方案。
现在 Alice 希望总费用尽量小,而Bob希望总费用尽量大。我们想知道, 如 果两个人都执行最优策略 ,最大流的值和总费用分别为多少。
分析
我们先分析Bob加费用的边一定要满足什么条件?
经过计算,Bob放的边一定是流量最大的!
而我们现在从Alice的角度想,就是保证最大流的同时使得流量最大的边最小。
咦,这句话好像在哪里听过,嗯没错,就是二分!
现在我们考虑如何二分判定,我们二分的是最大流量,又要求要留出最大流。
故,我们便可以二分完后截取每条边的流量:
f(u,v)=min(f(u,v),mid)
然后跑遍最大流,看看是否跑得出来。
var
x,y,n,m,p,nu,i:longint;
l,r,mid,z,ans:extended;
b,las,nex:array[1..100000] of longint;
f,re:array[1..100000] of extended;
dis,d:array[1..1000] of longint;
function max(l,r:extended):extended;
begin
if l<r then exit(r);exit(l);
end;
procedure insert(x,y:longint;z:extended);
begin
inc(nu);b[nu]:=y;nex[nu]:=las[x];las[x]:=nu;f[nu]:=z;re[nu]:=z;
inc(nu);b[nu]:=x;nex[nu]:=las[y];las[y]:=nu;f[nu]:=0;re[nu]:=0;
end;
function bfs:boolean;
var l,r,p:longint;
begin
l:=0;r:=1;fillchar(dis,sizeof(dis),0);dis[1]:=1;d[1]:=1;
while l<r do begin inc(l); p:=las[d[l]];
while p<>0 do begin
if (f[p]>0)and(dis[b[p]]=0) then begin
inc(r);d[r]:=b[p];dis[b[p]]:=dis[d[l]]+1;
end;p:=nex[p];end;
end;
exit(dis[n]<>0);
end;
function min(l,r:extended):extended;
begin
if l<r then exit(l);exit(r);
end;
function ditch(x:longint;y:extended):extended;
var p:longint;o:extended;
begin
if x=n then exit(y);
p:=las[x];ditch:=0;
while p<>0 do begin
if (f[p]>0)and(dis[b[p]]=dis[x]+1) then begin
o:=ditch(b[p],min(y,f[p]));
if o>0 then begin
f[p]:=f[p]-o;f[p xor 1]:=f[p xor 1]+o;ditch:=ditch+o;y:=y-o;end;
end;
p:=nex[p];
end;
if ditch=0 then dis[x]:=-1;
end;
function check(x:extended):boolean;
var i:longint;an:extended;
begin
for i:=2 to nu do begin
f[i]:=re[i];
if f[i]>x then f[i]:=x;
end;
an:=0;
while bfs do an:=an+ditch(1,maxlongint);
exit(an=ans);
end;
begin
readln(n,m,p);nu:=1;
for i:=1 to m do begin
readln(x,y,z);
insert(x,y,z);
r:=max(r,z);
end;
while bfs do
ans:=ans+ditch(1,maxlongint);
writeln(ans:0:0);
l:=0;
while r-l>0.00001 do begin
mid:=(l+r)/2;
if check(mid) then r:=mid else l:=mid+0.00001;
end;
writeln(l*p:0:4);
end.