这几天都在准备会考没时间写题,这道题算是这几天唯一的成果了....
会考求A...
下面进入正题。
Description
DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用。
DZY喜欢在地里散步。他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或触碰(出发点除外)。记这条封闭路线内部的格子总价值为V,路线上的费用总和为C,DZY想知道V/C的最大值是多少。
Analysis
题目要求使一个比值最大,那么我们便可以二分答案g,求MAX(V-gC)。
先将所有格子的价值加起来,然后便可以转化成最大权闭合图的模型,每个点向汇点T连边,容量为该格子的价值,表示不选该点就会失去该价值。源点S向每个在边界上的点连边,容量为该点边界(一条或两条边)的费用和*g,表示选了该点必须要支付这么多代价。然后每两个有公共边的格子连两条有向边,容量为公共边费用*g,表示若一个在S集一个在T集的话,必须要支付的代价。然后求一遍最小割。若最小割<价值和,那么该答案可行,l=mid;若最小割=价值和,那么不可行,r=mid。
还有精度不要太大,刚开始我定了1e-8结果RE了= =|||
上代码:
const lim=1e-6;
var
n,m,i,j,edge,vs,vt,num,sum:longint;
a,b,c:array[0..51,0..51] of longint;
e:array[1..800000,1..2] of longint;
ee:array[1..800000] of extended;
fr,d,vd:array[0..2510] of longint;
l,r,mid,u,ans,tmp:extended;
procedure add(x,y:longint;c:extended);
begin
inc(edge); e[edge,1]:=y; e[edge,2]:=fr[x]; ee[edge]:=c; fr[x]:=edge;
end;
function dcmp(d:extended):longint;
begin
if abs(d)<lim then exit(0);
if d<0 then exit(-1) else exit(1);
end;
function get(x,y:longint):longint;
begin
get:=(x-1)*m+y;
if (get<1) or (get>n*m) then get:=vt-1;
end;
function max(a,b:extended):extended;
begin
if a>b then exit(a) else exit(b);
end;
function min(a,b:extended):extended;
begin
if a<b then exit(a) else exit(b);
end;
function dfs(u:longint;flow:extended):extended;
var
k:longint;
tmp:extended;
begin
if u=vt then exit(flow);
dfs:=0;
k:=fr[u];
while k<>0 do begin
if (dcmp(ee[k])=1) and (d[u]=d[e[k,1]]+1) then begin
tmp:=dfs(e[k,1],min(ee[k],flow-dfs));
dfs:=dfs+tmp;
ee[k]:=ee[k]-tmp;
if odd(k) then ee[k+1]:=ee[k+1]+tmp else ee[k-1]:=ee[k-1]+tmp;
if dcmp(dfs-flow)=0 then exit;
end;
k:=e[k,2];
end;
dec(vd[d[u]]);
if vd[d[u]]=0 then d[vs]:=num;
inc(d[u]);
inc(vd[d[u]]);
end;
begin
readln(n,m);
for i:=1 to n do
for j:=1 to m do begin
read(a[i,j]);
sum:=sum+a[i,j];
end;
for i:=1 to n+1 do
for j:=1 to m do
read(b[i,j]);
for i:=1 to n do
for j:=1 to m+1 do
read(c[i,j]);
vs:=0; vt:=n*m+1; num:=vt+1;
l:=0; r:=1000000;
repeat
mid:=(l+r)/2;
fillchar(d,sizeof(d),0);
fillchar(vd,sizeof(vd),0);
fillchar(fr,sizeof(fr),0);
vd[0]:=num;
for i:=1 to n do
for j:=1 to m do begin
add(vs,get(i,j),a[i,j]);
add(get(i,j),vs,0);
end;
for i:=1 to n do
for j:=1 to m do begin
tmp:=0;
if i=1 then tmp:=tmp+b[i,j];
if i=n then tmp:=tmp+b[i+1,j];
if j=1 then tmp:=tmp+c[i,j];
if j=m then tmp:=tmp+c[i,j+1];
add(get(i,j),vt,tmp*mid);
add(vt,get(i,j),0);
end;
for i:=1 to n-1 do
for j:=1 to m do begin
add(get(i,j),get(i+1,j),b[i+1,j]*mid);
add(get(i+1,j),get(i,j),b[i+1,j]*mid);
end;
for i:=1 to n do
for j:=1 to m-1 do begin
add(get(i,j),get(i,j+1),c[i,j+1]*mid);
add(get(i,j+1),get(i,j),c[i,j+1]*mid);
end;
ans:=0;
while d[vs]<num do ans:=ans+dfs(vs,maxlongint);
tmp:=sum-ans;
if dcmp(tmp)>0 then l:=mid else r:=mid;
until r-l<=lim;
writeln(l:0:3);
end.