题目大意:有向图,点有点权,边有边权,奶牛想要从某点出发,走一些路使得经过的点权和除以边权和最大
题解:经典的最优比例环问题,01分数规划
根据问题的定义,ai为点权,bi为边权
二分答案L,最大化L,将边权改为原边权∗L−边终点的点权,计算F(L),若小于0则增大L,这个通过负环来求
我的收获:分数规划get
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define eps 1e-4
#define N 1005
#define M 5005
int n,m,t;
int f[N],head[N];
bool flag,mark[N];
double dis[N];
struct edge{int to,nex,str;double val;}e[M];
void add(int u,int v,int w){e[t].to=v,e[t].nex=head[u],e[t].str=w;head[u]=t++;}
void rebuild(double x)
{
for(int i=1;i<=n;i++)
for(int j=head[i];j!=-1;j=e[j].nex)
e[j].val=e[j].str*x-f[e[j].to];
}
void spfa(int x)
{
mark[x]=1;
for(int v,i=head[x];i!=-1;i=e[i].nex)
if(dis[v=e[i].to]>dis[x]+e[i].val){
if(mark[v]){flag=1;return;}
else dis[v]=dis[x]+e[i].val,spfa(v);
}
mark[x]=0;
}
bool ok()
{
for(int i=1;i<=n;i++) dis[i]=mark[i]=0;
flag=0;
for(int i=1;i<=n;i++){spfa(i);if(flag) return 1 ;}
return 0;
}
void work()
{
double ans;
for(double l=0,r=10000;r-l>eps;){
double mid=(l+r)/2.0;
rebuild(mid);
if(ok()) l=mid,ans=mid;
else r=mid;
}
printf("%.2lf",ans);
}
void init()
{
cin>>n>>m;
memset(head,-1,sizeof(head));t=0;
for(int i=1;i<=n;i++) scanf("%d",&f[i]);
int x,y,z;
for(int i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),add(x,y,z);
}
int main()
{
init();
work();
return 0;
}