分析:
01分数规划:最优比率环
求
∑val[i]∑e[i]
∑
v
a
l
[
i
]
∑
e
[
i
]
其中
val
v
a
l
是环中点的价值,
e
e
是环中边的价值
设答案为
则对于所有环都有:
∑val[i]∑e[i]<=ans
∑
v
a
l
[
i
]
∑
e
[
i
]
<=
a
n
s
ans∗∑e[i]−∑val[i]>=0
a
n
s
∗
∑
e
[
i
]
−
∑
v
a
l
[
i
]
>=
0
对于答案
k
k
:
当时,就存在至少一个环
k∗∑e[i]−∑val[i]<0
k
∗
∑
e
[
i
]
−
∑
v
a
l
[
i
]
<
0
,即有负权回路(边权为
k∗e[i]−val[i]
k
∗
e
[
i
]
−
v
a
l
[
i
]
)
当
k>=ans
k
>=
a
n
s
时,就对于所有的环
k∗∑e[i]−∑val[i]>=0
k
∗
∑
e
[
i
]
−
∑
v
a
l
[
i
]
>=
0
,即没有负权回路
二分答案,把边权设 为
mid∗w(x,y)−val[x]
m
i
d
∗
w
(
x
,
y
)
−
v
a
l
[
x
]
,判断是否有负环
有则放大范围,无则缩小范围
tip
dis[y]=min(dis[x]+mid∗w(x,y)−val[x]) d i s [ y ] = m i n ( d i s [ x ] + m i d ∗ w ( x , y ) − v a l [ x ] )
还是要分清楚这几个单词的意思:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
const double eps=1e-6;
const int N=5002;
struct node{
int y,nxt;
double v;
};
node way[N];
int n,m,st[N],tot=0,cnt[N];
double val[N],dis[N];
bool in[N];
void add(int u,int w,double z) {
tot++;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
int spfa(double x) {
queue<int> Q;
for (int i=1;i<=n;i++) { //多源
in[i]=1; dis[i]=0; Q.push(i); cnt[i]=0;
}
while (!Q.empty()) {
int now=Q.front(); Q.pop();
in[now]=0;
for (int i=st[now];i;i=way[i].nxt) {
int y=way[i].y;
if (dis[now]+x*way[i].v-val[now]<dis[y]) {
dis[y]=dis[now]+x*way[i].v-val[now];
if (!in[y]) {
in[y]=1;
Q.push(y);
if (++cnt[y]>n) return 1;
}
}
}
}
return 0;
}
int main()
{
double l=0,r=0,ans=0;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lf",&val[i]),r=max(r,val[i]);
for (int i=1;i<=m;i++) {
int u,w; double z;
scanf("%d%d%lf",&u,&w,&z);
add(u,w,z);
}
while (r-l>=eps) {
double mid=(l+r)/2;
if (spfa(mid)) ans=mid,l=mid;
else r=mid;
}
printf("%0.2lf\n",ans);
return 0;
}