zoukankan      html  css  js  c++  java
  • uva11090(spfa判负环)

    题目连接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2031

    自己没想出,其实也不难。

    首先判断图中是否存在环,若不存在则No cycle found.

    若存在:

    可知lowest mean的范围是介于最大权和最小权之间的。

    可以二分,查找符合条件的最小值。

    mid满足的条件是,存在k条边,使得w1+w2+w3+……+wk<k*mid;

    上式可变形为 (w1-mid)+(w2-mid))+……+(wk-mid)<0; 即判断负环。

    开始只判断了从1开始是否存在负环,WA几次才意识到问题,负环可能不含点1。。

    虚拟一个结点0,到各个点距离为0. 从节点0开始入队即可查找全图是否存在负环。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 #include<algorithm>
      5 using namespace std;
      6 
      7 const double eps=1e-8;
      8 const int inf=0x3f3f3f3f;
      9 const int maxn=110;
     10 
     11 struct edge
     12 {
     13     int v,nex;
     14     double w;
     15 }e[maxn*maxn];
     16 
     17 int head[maxn],cnt=0;
     18 int inq[maxn],vis[maxn];
     19 double dis[maxn];
     20 int n,m;
     21 
     22 void add(int u,int v,double w)
     23 {
     24     e[cnt].v=v;
     25     e[cnt].w=w;
     26     e[cnt].nex=head[u];
     27     head[u]=cnt++;
     28 }
     29 int spfa()
     30 {
     31     queue<int> q;
     32     for(int i=1;i<=n;i++) //虚拟节点0
     33     {
     34         dis[i]=0;
     35         vis[i]=1;
     36         inq[i]=1;
     37         q.push(i);
     38     }
     39     while(!q.empty())
     40     {
     41         int u=q.front();
     42         q.pop();
     43         inq[u]=0;
     44         for(int i=head[u];i!=-1;i=e[i].nex)
     45         {
     46             int v=e[i].v;
     47             if(dis[v]>dis[u]+e[i].w)
     48             {
     49                 dis[v]=dis[u]+e[i].w;
     50                 if(!inq[v])
     51                 {
     52                     inq[v]=1;
     53                     vis[v]++;
     54                     if(vis[v]>n) return 1;
     55                     q.push(v);
     56                 }
     57             }
     58         }
     59     }
     60     return 0;
     61 }
     62 int check(double x)
     63 {
     64     int ok=0;
     65     for(int i=0;i<cnt;i++)
     66         e[i].w-=x;
     67     if(spfa()) ok=1;
     68     for(int i=0;i<cnt;i++)
     69         e[i].w+=x;
     70     return ok;
     71 }
     72 int main()
     73 {
     74     int t;
     75     scanf("%d",&t);
     76     for(int c=1;c<=t;c++)
     77     {
     78         int u,v;
     79         double w,L=inf,R=0;
     80         memset(head,-1,sizeof(head));
     81         cnt=0;
     82         scanf("%d%d",&n,&m);
     83         for(int i=0;i<m;i++)
     84         {
     85             scanf("%d%d%lf",&u,&v,&w);
     86             add(u,v,w);
     87             L=min(L,w);
     88             R=max(R,w);
     89         }
     90         printf("Case #%d: ",c);
     91         if(!check(1+R))
     92             puts("No cycle found.");
     93         else
     94         {
     95             while(R-L>eps)
     96             {
     97                 double mid=L+(R-L)/2;
     98                 if(check(mid)) R=mid;
     99                 else L=mid;
    100             }
    101             printf("%.2lf
    ",R);
    102         }
    103     }
    104     return 0;
    105 }
  • 相关阅读:
    day15内置函数
    day14生成器进阶
    day13迭代器、生成器
    day12装饰器进阶
    day11装饰器
    day10函数进阶
    day9函数
    day8文件操作
    正则表达式
    初识递归
  • 原文地址:https://www.cnblogs.com/yijiull/p/6736651.html
Copyright © 2011-2022 走看看