uva11090【Going in Cycle】

来源:互联网 发布:sql存储过程解密工具 编辑:程序博客网 时间:2024/05/21 11:20

 【题目大意】给定一个有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);    }  }


0 0