# [HNOI2009] 最小圈
## 题目描述
## 输入格式
第一行两个正整数,分别为 $n$ 和 $m$,并用一个空格隔开。其中 $n=|V|$,$m=|E|$ 分别表示图中有 $n$ 个点 和 $m$ 条边。
接下来 $m$ 行,每行三个数 $i,j,w_{i,j}$,表示有一条边 $(i,j)$ 且该边的权值为 $w_{i,j}$,注意边权可以是实数。输入数据保证图 $G=(V,E)$ 连通,存在圈且有一个点能到达其他所有点。
## 输出格式
一个实数 $\mu'(G)$,要求精确到小数点后 $8$ 位。
## 样例 #1
### 样例输入 #1
```
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
```
### 样例输出 #1
```
3.66666667
```
## 样例 #2
### 样例输入 #2
```
2 2
1 2 -2.9
2 1 -3.1
```
### 样例输出 #2
```
-3.00000000
```
## 提示
对于 $100\%$ 的数据,$2\leq n\le 3000$,$1\leq m\le 10000$,$|w_{i,j}| \le 10^7$,$1\leq i, j\leq n$ 且 $i\neq j$。
------------
提示:本题存在 $O(nm)$ 的做法,但是 $O(nm\log n)$ 的做法也可以通过。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define ld long double
#define eps 1e-10
//This code is written by Itst
using namespace std;
inline int read(){
int a = 0;
bool f = 0;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = 1;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << 3) + (a << 1) + (c ^ '0');
c = getchar();
}
return f ? -a : a;
}
const int MAXN = 3010 , MAXM = 10010;
struct Edge{
int end , upEd;
ld w;
}Ed[MAXM];
ld minDis[MAXN];
int head[MAXN] , flo[MAXN] , N , M , cntEd;
queue < int > q;
bool inq[MAXN] , vis[MAXN];
inline void addEd(int a , int b , ld c){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
Ed[cntEd].w = c;
}
/*bool SPFA(){
memset(minDis , 0 , sizeof(minDis));
for(int i = 1 ; i <= N ; ++i){
if(!inq[i]){
inq[i] = 1;
q.push(i);
}
flo[i] = 1;
}
while(!q.empty()){
int t = q.front();
q.pop();
inq[t] = 0;
for(int i = head[t] ; i ; i = Ed[i].upEd)
if(minDis[Ed[i].end] > minDis[t] + Ed[i].w + eps){
minDis[Ed[i].end] = minDis[t] + Ed[i].w;
flo[Ed[i].end] = flo[t] + 1;
if(flo[Ed[i].end] > N)
return 1;
if(!inq[Ed[i].end]){
inq[Ed[i].end] = 1;
q.push(Ed[i].end);
}
}
}
return 0;
}*/
bool SPFA(int now){
vis[now] = 1;
for(int i = head[now] ; i ; i = Ed[i].upEd)
if(minDis[Ed[i].end] > minDis[now] + Ed[i].w)
if(vis[Ed[i].end])
return 1;
else{
minDis[Ed[i].end] = minDis[now] + Ed[i].w;
if(SPFA(Ed[i].end))
return 1;
}
vis[now] = 0;
return 0;
}
inline void add(ld num){
for(int i = 1 ; i <= cntEd ; ++i)
Ed[i].w += num;
}
bool check(ld mid){
bool f = 0;
add(-mid);
memset(minDis , 0 , sizeof(minDis));
memset(vis , 0 , sizeof(vis));
for(int i = 1 ; !f && i <= N ; ++i)
if(minDis[i] > -1e-8 && minDis[i] < 1e-8)
f = SPFA(i);
add(mid);
return f;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("3199.in" , "r" , stdin);
//freopen("3199.out" , "w" , stdout);
#endif
N = read();
M = read();
for(int i = 1 ; i <= M ; ++i){
int a = read() , b = read();
ld c;
scanf("%Lf" , &c);
addEd(a , b , c);
}
ld L = -1e7 , R = 1e7;
while(R - L > eps){
ld mid = (L + R) / 2;
check(mid) ? R = mid : L = mid;
}
printf("%.8Lf" , L);
return 0;
}