在图中找一个环,使得环上边权之和除以节点个数最小,求这个最小平均值
题解
分数规划思想
二分平均值,然后对于每条边,我们都减去这个值
接着我们在图中找负环,如果负环存在,则说明答案过大,否则答案过小
代码
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxd = 1e4+10;
const int maxn = 3e3+10;
struct{
int v,net;
double w;
}e[maxd];
int f[maxn],eid,n,m;
bool vis[maxn];
double dist[maxn];
void insert(int a,int b,double c)
{
e[eid].v = b;
e[eid].w = c;
e[eid].net = f[a];
f[a] = eid++;
}
void init()
{
memset(f,-1,sizeof(f));
eid = 0;
}
bool dfs(int x,double mid)
{
vis[x] = 1;
for(int i=f[x];i+1;i=e[i].net)
{
int to = e[i].v;
if(dist[to] > dist[x] + e[i].w - mid)
{
dist[to] = dist[x] + e[i].w - mid;
if(vis[to] || dfs(to,mid))
{
vis[x] = 0;
return true;
}
}
}
vis[x] = 0; return false;
}
bool check(double mid)
{
memset(dist,0,sizeof(dist));
for(int i=1;i<=n;i++)
if(dfs(i,mid)) return true;
return false;
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("k.out","w",stdout);
int a,b,c;init();
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&a,&b,&c);
insert(a,b,(double)c);
}
double l = -1e7, r = 1e7,ans;
while(l<=r)
{
double mid = (l+r)/2;
if(check(mid))
{
ans = mid;
r = mid-0.000000001;
}
else l = mid + 0.000000001;
}
printf("%.8lf",ans);
return 0;
}