【题目大意】给定一个有n个顶点m条边的加权有向图,如果图中存在环(回路),环的平均值等于,环上边的权值之和除以构成环的边数,图中可能不止存在一个回路,计算平均权值最小的回路。
【题解】
最优比例环
用二分答案。假设答案为mid,只需要判断是否存在平均值小于mid的回路。
假设一个包含k条边的回路,回路上各条边的权值为w1,w2……wk,那么平均值小于mid意味着 w1+w2+……wk< k* mid即:
(w1-mid)+(w2-mid)+……(wk-mid)<0 (这个就是最优比例环的简化版点权为1)
换句话说,只要把图中每一条边a,b的权值w(a,b)变为w(a,b)-mid,在判断图中有没有负权回路。
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>
using namespace std;
double a[1500],d[1500],l,r,mid,o;
struct info
{
int ar,next;
double l;
}road[10005];
int first[1500],i,j,k,m,num,n,sum,q[1500],c[1500],f[1500],p1,q1,vis[1500],T;
void add(int x,int y,double len)
{
num++;
road[num].ar=y;road[num].next=first[x];
road[num].l=len;first[x]=num;
}
int spfa(double k,int z)
{
int i,h,t,u,v;
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
for (i=1;i<=n;i++) d[i]=1e9;
t=1;h=0;q[1]=z;d[z]=0;f[z]=1;c[z]=1;
for (;h!=t;)
{
h++;if (h==1500) h=0;u=q[h];f[u]=0;vis[u]=1;
for (i=first[u];i;i=road[i].next)
{
v=road[i].ar;
if (d[u]+road[i].l-a[v]*k<d[v])
{
d[v]=d[u]+road[i].l-a[v]*k;
if (!f[v])
{
t++;if (t==1500) t=0;
q[t]=v;f[v]=1;c[v]=c[u]+1;
if (c[v]>n) return 1;
}
}
}
}
return 0;
}
int pd(double k)
{
int i;
memset(vis,0,sizeof vis);
for (i=1;i<=n;i++)
if (!vis[i])
if (spfa(k,i)) return 1;
return 0;
}
int main()
{
for (sum=0,scanf("%d",&T);T;T--)
{
sum++;num=0;memset(first,0,sizeof first);
memset(vis,0,sizeof vis);
scanf("%d%d",&n,&m);r=0;l=0;
for (i=1;i<=n;i++) a[i]=1;
for (i=1;i<=m;i++)
{
scanf("%d%d%lf",&p1,&q1,&o);
add(p1,q1,o);
}
r=1e12;
for (;r-l>1e-5;)
{
mid=(l+r)/2;
if (pd(mid)) r=mid;else l=mid;
}
printf("Case #%d: ",sum);
if (r==1e12) printf("No cycle found.\n");else printf("%.2f\n",r);
}
}