Description
对于一张有向图, 求最小的圈平均值,即若一颗圈经过 k k 个节点,那么一个圈的平均值为圈上 k k 条边权的和除以 k k ,现要求其中的最小值。
Input
第一行
2
2
个正整数,分别为
n
n
和
m
m
以下
m
m
行,每行
3
3
个数,表示边连接的信息
Output
一行一个数,表示最小圈的值。你的答案被视为正确当且仅当与标准答案的绝对误差不超过 1e−5 1 e − 5
Data Constraint
20%:n<=100,m<=1000
20
%
:
n
<=
100
,
m
<=
1000
60%:n<=1000,m<=5000
60
%
:
n
<=
1000
,
m
<=
5000
100%:n<=3000,m<=10000
100
%
:
n
<=
3000
,
m
<=
10000
abs(Wi,j)<=105
a
b
s
(
W
i
,
j
)
<=
10
5
Sample Input
输入1:
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
输入2:
2 2
1 2 -2.9
2 1 -3.1
Sample Output
输出1:
3.666667
输出2:
-3.000000
Solution
二分答案,分数规划,将求值问题变成可行性判断问题。
然后要利用深搜版
SPFA
S
P
F
A
或者
dfs
d
f
s
,用于判负环,来求可行性,如果是宽搜的话会被
T
T
。
原理:
若事先把所有边加上或减去一个值,则相应地会增大或减少所有圈的平均值。假设存在一个
ans
a
n
s
待判断,那么我们把所有边减去
ans
a
n
s
后
spfa
s
p
f
a
一下,当
dis>0
d
i
s
>
0
时不再走下去。若最终找到一个负环,说明
ans
a
n
s
答案是可行的,修改上界,否则修改下界。而这最终结果是得到一个
ans
a
n
s
,然后
spfa
s
p
f
a
得到一个
dis=0
d
i
s
=
0
的环。
Code
const maxn=3005;
maxm=10005;
e=0.000001;
var tot,i,n,m:longint;
l,r,mid:real;
p:boolean;
cost,w:array[1..maxm] of real;
next,yy,u,v:array[1..maxm] of longint;
g:array[1..maxn] of longint;
dis:array[1..maxn] of real;
vis:array[1..maxn] of boolean;
procedure make(x,y:longint;z:real);
begin
inc(tot);
yy[tot]:=y;
cost[tot]:=z;
next[tot]:=g[x];
g[x]:=tot;
end;
procedure spfa(x:longint);
var i,y:longint;
begin
vis[x]:=true;
i:=g[x];
while i<>0 do begin
y:=yy[i];
if dis[x]+cost[i]<dis[y] then begin
if vis[y] then begin
p:=true;
break;
end;
dis[y]:=dis[x]+cost[i];
spfa(y);
if p then break;
end;
i:=next[i];
end;
vis[x]:=false;
end;
function judge(x:real):boolean;
begin
tot:=1;p:=false;
fillchar(next,sizeof(next),0);
fillchar(g,sizeof(g),0);
fillchar(cost,sizeof(cost),0);
fillchar(yy,sizeof(yy),0);
fillchar(vis,sizeof(vis),false);
fillchar(dis,sizeof(dis),0);
for i:=1 to m do make(u[i],v[i] ,w[i]-x);
for i:=1 to n do begin
spfa(i);
if p then exit(p);
end;
exit(false);
end;
begin
readln(n,m);
for i:=1 to m do readln(u[i],v[i],w[i]);
l:=-100005;r:=100005;
while l+e<r do begin
mid:=(l+r)/2;
if judge(mid) then r:=mid else l:=mid+e;
end;
writeln(l:0:6);
end.