题目大意:
求有向带权图中的最小平均值圈,平均值定义为边的权和与点数的比值
题解:
标准的01分数规划
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 3010;
const int maxm = 10010;
const double eps = 1e-12;
struct Edge{
int to,next;
double dis;
}G[maxm<<1];
int head[maxn],cnt;
void add(int u,int v,double d){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
G[cnt].dis = d;
}
#define v G[i].to
bool inq[maxn];double dis[maxn];
bool dfs(int u){
inq[u] = true;
for(int i = head[u];i;i=G[i].next){
if(dis[v] > dis[u] + G[i].dis){
dis[v] = dis[u] + G[i].dis;
if(inq[v]) return true;
if(dfs(v)) return true;
}
}inq[u] = false;
return false;
}
#undef v
int n;
inline bool check(double mid){
for(int i=1;i<=cnt;++i) G[i].dis -= mid;
memset(inq,0,sizeof inq);memset(dis,0,sizeof dis);
bool flag = false;
for(int i=1;i<=n;++i) if(dfs(i)){flag = true;break;}
for(int i=1;i<=cnt;++i) G[i].dis += mid;
return flag;
}
int main(){
int m;read(n);read(m);
double d;
for(int i=1,u,v;i<=m;++i){
read(u);read(v);scanf("%lf",&d);
add(u,v,d);
}
double l = -1e9,r = 1e9;
while(r-l > eps){
double mid = (l+r)/2;
if(check(mid)) r = mid;
else l = mid;
}printf("%.8lf\n",r);
getchar();getchar();
return 0;
}