这道题是一道标准的01分数规划:
但是有一些细节可以优化:
不难想到要二分一个mid然后判定图上是否存在一个环S,该环是否满足∑i=1t(Fun[vi]−mid∗Tim[ei])>0
但是上面的算法并不好实现,所以可以将两边同时乘上-1,使式子变为∑i=1t?(mid∗Tim[ei?]−Fun[vi?])<0
那么该问题就转化成了在每一个图中跑一边SPFA来寻找是否存在负环,若存在则l=mid,否则r=mid;
#include <bits/stdc++.h> #define inc(a,b,c) for(register int i=a;i<=b;i+=c) #define ini 20010 using namespace std; int n,m; struct littlestar{ int from; int to; int nxt; double w; }star[ini],star2[ini]; int head[ini],cnt,head2[ini]; void add(int u,int v,int w) { star[++cnt].to=v; star[cnt].nxt=head[u]; star[cnt].from=u; star[cnt].w=w; head[u]=cnt; } int c[ini]; queue<int> q; double dis[ini]; int vis[ini]; int SPFA() { int tot=0; for(int i=1;i<=n;i++){ q.push(i); dis[i]=0; vis[i]=1; } while(q.size()){ int u=q.front(); q.pop(); vis[u]=0; for(int i=head2[u];i;i=star2[i].nxt){ int v=star2[i].to; if(dis[v]>dis[u]+star2[i].w){ dis[v]=dis[u]+star2[i].w; if(vis[v]==0){ vis[v]=1; q.push(v); ++tot; if(tot>2*(n+m)) return 0; } } } } return 1; } int check(double x) { inc(1,cnt,1){ star2[i]=star[i]; star2[i].w=(double)star[i].w*(double)x-(double)c[star[i].from]; } inc(1,n,1){ head2[i]=head[i]; } if(SPFA()){ return 0; } else{ return 1; } } int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘; ch=getchar();} return x*f; } int main() { n=read(); m=read(); inc(1,n,1) c[i]=read(); inc(1,m,1){ int u,v,w; u=read();v=read();w=read(); add(u,v,w); } double l=0.00,r=1000010.000,mid; while(r-l>1e-4){ mid=(l+r)/2; if(check(mid)){ l=mid; } else{ r=mid; } } printf("%.2lf",l); }
洛谷 P2868 [USACO07DEC]观光奶牛Sightseeing Cows 题解
原文:https://www.cnblogs.com/kamimxr/p/11545032.html