分数规划的标准做法,先二分答案,然后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;
}