题意:n*m的方格,每个方格有一个收益,每一条单位长度的方格线都一定费用,从任意格点出发,沿着格线行走至到出发点,收益为形成的封闭图形内的方格的收益,总费用为走的格线的费用和,求 总收益/总费用 的最大值
第一眼显然01分数规划...,需要想办法维护形成的封闭图形的总收益
我们默认他是逆时针走的
这样,利用差分的思想,我们把从下往上走的边的收益定义为这一行它左边的收益和,把从左往右走的的收益定义为这一列它上边的权益和,把从上往下走的收益定义为这一行它左边的收益和的相反数,把从右往左的收益定义为这一列它上边的权益和的相反数,这样就可以跑01分数规划了,最后把答案除以2就行了
const
eps=1e-6;
var
n,m,x,l :longint;
i,j :longint;
flag :boolean;
ll,r,mid :double;
a,b,pre,other :array[0..11010] of longint;
last :array[0..3605] of longint;
num,sl,sr :array[0..55,0..55] of longint;
vis :array[0..3605] of boolean;
d :array[0..11010] of double;
dis :array[0..3605] of double;
procedure connect(x,y,aa,bb:longint);
begin
inc(l);
pre[l]:=last[x];
last[x]:=l;
other[l]:=y;
a[l]:=aa;
b[l]:=bb;
end;
procedure dfs(x:longint);
var
p,q:longint;
begin
if flag then exit;
vis[x]:=true;
q:=last[x];
while (q<>0) do
begin
if flag then exit;
p:=other[q];
if dis[p]>dis[x]+d[q] then
begin
dis[p]:=dis[x]+d[q];
if vis[p] then
begin
flag:=true; exit;
end else dfs(p);
end;
q:=pre[q];
end;
vis[x]:=false;
end;
function check(ll:double):boolean;
var
i:longint;
begin
flag:=false;
fillchar(dis,sizeof(dis),0);
fillchar(vis,sizeof(vis),false);
for i:=1 to l do d[i]:=-(a[i]-ll*b[i]);
for i:=1 to (n+1)*(m+1) do
begin
dfs(i);
if flag then exit(true);
end;
exit(false);
end;
begin
read(n,m);
for i:=1 to n do
for j:=1 to m do
begin
read(x);
sl[i,j]:=sl[i,j-1]+x;
sr[i,j]:=sr[i-1,j]+x;
end;
//
for i:=1 to n+1 do
for j:=1 to m+1 do num[i,j]:=(i-1)*(m+1)+j;
//
for i:=1 to n+1 do
for j:=1 to m do
begin
read(x);
connect(num[i,j],num[i,j+1],sr[i-1,j],x);
connect(num[i,j+1],num[i,j],-sr[i-1,j],x);
end;
//
for i:=1 to n do
for j:=1 to m+1 do
begin
read(x);
connect(num[i+1,j],num[i,j],sl[i,j-1],x);
connect(num[i,j],num[i+1,j],-sl[i,j-1],x);
end;
//
ll:=0; r:=1e6;
while (r-ll>=eps) do
begin
mid:=(ll+r)/2;
if check(mid) then ll:=mid else r:=mid;
end;
ll:=ll/2;
writeln(ll:0:3);
end.
——by Eirlys