题目大意:给出一个有向图,求这个图的路径长度平均值最小的环。
思路:二分这个答案,然后将所有边权都减去这个二分的值,对于所有节点进行DFS,这个过程中只沿着长度不断减少的方向搜,如果搜回了自己,说明可以降低界,否则提升下界。
不要用SPFA判负环,因为会T。
CODE:
#include <cmath>
#include <cstdio>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 3010
#define MAXE 10010
#define INF 1e10
#define EPS 1e-12
using namespace std;
int points,edges;
double len;
int head[MAX],total;
int next[MAXE],aim[MAXE];
double length[MAXE];
inline void Add(int x,int y,double len)
{
next[++total] = head[x];
aim[total] = y;
length[total] = len;
head[x] = total;
}
bool v[MAX];
double mid,f[MAX];
void DFS(int x)
{
if(v[x]) throw true;
v[x] = true;
for(int i = head[x]; i; i = next[i])
if(f[x] + length[i] - mid < f[aim[i]]) {
f[aim[i]] = f[x] + length[i] - mid;
DFS(aim[i]);
}
v[x] = false;
}
double l = -INF,r = INF;
int main()
{
cin >> points >> edges;
for(int x,y,i = 1; i <= edges; ++i) {
scanf("%d%d%lf",&x,&y,&len);
Add(x,y,len);
l = min(l,len);
r = max(r,len);
}
while(fabs(r - l) > EPS) {
mid = (l + r) / 2.0;
bool flag = false;
for(int i = 1; i <= points; ++i) {
try {
memset(f,0,sizeof(f));
memset(v,false,sizeof(v));
DFS(i);
}catch(bool) {
flag = true;
break;
}
}
if(flag) r = mid;
else l = mid;
}
if(fabs(l) < EPS) cout << "0.00000000" << endl;
else cout << fixed << setprecision(8) << l << endl;
return 0;
}