题目链接
题目描述
DZY家的后院有一块地,由N行M列的方格组成,格子内种的菜有一定的价值,并且每一条单位长度的格线有一定的费用。
DZY喜欢在地里散步。他总是从任意一个格点出发,沿着格线行走直到回到出发点,且在行走途中不允许与已走过的路线有任何相交或触碰(出发点除外)。记这条封闭路线内部的格子总价值为V,路线上的费用总和为C,DZY想知道V/C的最大值是多少。
Sol
分数规划
一个封闭图形可以在走的时候把边权该为 原边权 减去(加上) 这一列格子价值的前缀和
可以规定向左走为正 , 向右走为负
然后就是 边权取反+判负圈 了 (这个是真的难搞TAT)
堆栈版SPFA , 不要求最短路不要设 dis 为INF !!! 直接都相同即可
因为一个负圈必然可以找到一种走法,使得边权一直为负(似乎是这样) !!!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstdlib>
#include<set>
#define Set(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
typedef long long ll;
typedef double db;
const int N=52;
const int MAXN=N*N;
const db INF=1e9;
const db eps=1e-5;
db V[MAXN];
int n,m;
struct edge{
int to,next;int len;db w;int id;bool flag;
}a[8*MAXN];
int head[MAXN];int cnt=0;
int S,T;
bool in[MAXN];
db dis[MAXN];
inline void add(int x,int y,int w,bool fl){a[++cnt]=(edge){y,head[x],w,0.0,0,fl};head[x]=cnt;}
bool dfs(int u)
{
if(in[u]) return 1;
in[u]=1;
for(register int v,i=head[u];i;i=a[i].next){
v=a[i].to;
if(dis[v]>dis[u]+a[i].w){
dis[v]=dis[u]+a[i].w;
bool g=dfs(v);
if(g) return 1;
}
}
in[u]=0;
return 0;
}
inline bool check(db X)
{
for(register int i=1;i<=cnt;++i){
if(a[i].flag==1) a[i].w=V[a[i].id]-(db)a[i].len*X;
else a[i].w=-V[a[i].id]-(db)(a[i].len*X);
a[i].w=-a[i].w;
}
Set(dis,0);Set(in,0);
for(register int i=1;i<=T;++i) if(dfs(i)) return 1;
return 0;
}
int main()
{
n=read();m=read();int h=0;T=(n+1)*(m+1);S=0;
for(register int i=1;i<=n;++i) for(register int j=1;j<=m;++j) V[++h]=read();
h=m;
for(register int i=2;i<=n;++i) for(register int j=1;j<=m;++j) V[++h]+=V[h-m];
h=0;V[0]=0.0;
for(register int i=1;i<=n+1;++i)
for(register int j=1;j<=m;++j){
++h;register int w=read();
add(h,h+1,w,1);a[cnt].id=max(0,h-m-i+1);
add(h+1,h,w,0);a[cnt].id=max(0,h-m-i+1);
if(j==m) ++h;
}
h=0;
for(register int i=1;i<=n;++i){
for(register int j=1;j<=m+1;++j){
++h;register int w=read();
add(h,h+m+1,w,0);add(h+m+1,h,w,0);
}
}
register db l=1.0,r=250000.00,ans=0.0;
while(r-l>=eps){
register db mid=(l+r)/2.000;
if(check(mid)) l=mid,ans=mid;
else r=mid;
}
printf("%.3lf\n",ans);
}