题意:给你一幅图,点上有收益,边上有花费,让你走过一段路,使得收益和/花费和最大。。
一开始各种奇怪方法上,因为从来没做过01分数规划= =。。
其中看起来最像正解的应该是spfa的时候两个一起更新,把花费和收益都搞到边上去,但是sb的我没有发现,题目要求是一个环!!!!!!!!!!!
01分数规划也不是很难,推荐一篇讲的很好的文章。
http://www.cnblogs.com/perseawe/archive/2012/05/03/01fsgh.html
然后其实就是最优比率环了,把d[i]赋值到边上去,然后直接做spfa(最长路)啊,
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
int n, m;
const int N = 3e5 + 5;
unsigned int read()
{
unsigned 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;
}
typedef double db;
const db eps = 1e-5;
int tot;
db mid;
db dis[N],ans;
bool vis[N];
int head[N], nxt[N], go[N], val[N], a[N];
inline void add(int x, int y, int z)
{
go[++tot] = y;
nxt[tot] = head[x];
val[tot] = z;
head[x] = tot;
}
inline bool spfa(int x)
{
vis[x] = 1;
for (int i = head[x]; i; i = nxt[i])
{
int v = go[i];
db value = a[v] - mid*val[i];
if (dis[v]<dis[x]+value)
{
if (!vis[v])
{
dis[v] = dis[x] + value;
if (spfa(v))return 1;
}
else return 1;
}
}
return vis[x]=0;//不成功的点注意退回标记
}
int main()
{
n = read(); m = read();
fo(i, 1, n)a[i] = read();
fo(i, 1, m)
{
int x=read(),y=read(),z=read();
add(x, y, z);
}
db l = 0.0, r = 1000.0;
while (r - l > eps)
{
memset(dis, 254, sizeof(dis));//填的是负数
memset(vis, 0, sizeof(vis));
dis[1] = 0.0;
mid = (l + r) / 2.0;
if (spfa(1))ans = mid, l = mid;
else r = mid;
}
printf("%.2lf\n", ans);
}