分数规划的标准做法,先二分答案,然后spfa找正环。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn=1e3+9,maxm=5e3+9; double a[maxn]; int head[maxn],lon; struct { int to,next,w; }e[maxm<<1]; void edgeini() { memset(head,-1,sizeof(head)); lon=-1; } void edgemake(int from,int to,int w) { e[++lon].to=to; e[lon].w=w; e[lon].next=head[from]; head[from]=lon; } int n,m,que[maxn*maxn],in[maxn]; double dist[maxn]; bool text[maxn]; bool spfa(double ret) { int front=1,end=0; for(int i=1;i<=n;i++) { que[++end]=i; dist[i]=in[i]=0; text[i]=1; } while(front<=end) { int t=que[front++]; if(in[t]>n) return true; text[t]=0; for(int k=head[t];k!=-1;k=e[k].next) { int u=e[k].to; if(dist[u]<dist[t]+a[u]-ret*e[k].w) { dist[u]=dist[t]+a[u]-ret*e[k].w; if(!text[u]) { text[u]=1; que[++end]=u; in[u]++; } } } } return false; } int main() { while(scanf("%d %d",&n,&m)!=EOF) { edgeini(); for(int i=1;i<=n;i++) scanf("%lf",&a[i]); for(int i=1,from,to,w;i<=m;i++) { scanf("%d %d %d",&from,&to,&w); edgemake(from,to,w); } double l=0,r=1e3+9,m; while(r-l>1e-4) { m=(l+r)/2; if(spfa(m)) l=m; else r=m; } printf("%.2f\n",l); } return 0; }