H - Going in Cycle!! (UVA - 11090)

- 题目大意

给你一个有向图,问你定义一个环的平均值为这个环上所有边的平均值,问你最小的环的平均值是多少。

- 解题思路

先利用spfa来判断负环,然后用二分去判断若当前的二分值是mid,让所有的边都减去这个值,如果此时图中出现负环,则说明有环的平均值比这个更小。

- 代码

#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
using namespace std;
const int N=500;
const int M=1e6+5;
const int INF=0x3f3f3f;
int n,m;
struct edge {
    int v,next;
    double w;
}e[M*2];
int head[N], cnt;
double d[N];
int inq[N];
int cn[N];
void init ()
{
    cnt=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,double c)
{
    e[cnt].w=c;
    e[cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
bool SPFA(int s) {
    memset(d, INF, sizeof(d));
    memset(inq, 0, sizeof(inq));
    memset(cn, 0, sizeof(cn));
    queue<int> Q;
    Q.push(s);
    d[s] = 0;
    inq[s] = 1;
    while(Q.size()) {
        int u = Q.front();
        Q.pop();
        inq[u] = 0;
        for(int i = head[u]; ~i; i = e[i].next)
        {
            int v = e[i].v;
            double w = e[i].w;
            if(d[v] > d[u] + w)
            {
                d[v] = d[u] + w;
                if(!inq[v])
                {
                    Q.push(v);
                    inq[v] = 1;
                    if(++cn[v] >= n)
                        return false;
                }
            }
        }
    }
    return true;
}

bool check(double x)
{
    bool vis=false;
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j!=-1;j=e[j].next)
            e[j].w-=x;
    }
    for(int i=1;i<=n;i++)
    {
        if(!SPFA(i))
            vis=true;
    }
     for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j!=-1;j=e[j].next)
            e[j].w+=x;
    }
    return vis;
}

int main()
{
    int t,a,b;
    double c;
    scanf("%d",&t);
    for(int k=1;k<=t;k++)
    {
        double l=INF,r=0,mid;
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%lf",&a,&b,&c);
            addedge(a,b,c);
            l=min(l,c);
            r=max(r,c);
        }
        printf("Case #%d: ",k);
        if(!check(r+1))
             printf("No cycle found.\n");
        else
        {
            while(r-l>1e-8)
            {
                mid=(r+l)/2;
                if(check(mid))
                    r=mid;
                else
                    l=mid;
            }
            printf("%.2lf\n",r);
        }
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/alpacadh/p/8449749.html

时间: 2024-08-09 16:14:37

H - Going in Cycle!! (UVA - 11090)的相关文章

训练指南 UVA - 11090(最短路BellmanFord+ 二分判负环)

layout: post title: 训练指南 UVA - 11090(最短路BellmanFord+ 二分判负环) author: "luowentaoaa" catalog: true mathjax: true tags: - 最短路 - 基础DP - BellmanFord - 图论 - 训练指南 Going in Cycle!! UVA - 11090 题意 就最小的环的平均权值 题解 分枚举平均值mid,只需判断是否存在平均值小于mid的回路,即判断是否有sum(wi)&

UVA 11090 - Going in Cycle!!(Bellman-Ford)

UVA 11090 - Going in Cycle!! 题目链接 题意:给定一个有向图,球平均权值最小的回路 思路:二分+判负环,每次二分一个值mid,判断是否存在小于mid的环,那么就是(w1 + w2 + w3...) / n < mid == w1 - mid + w2 - mid + w3 - mid .... < 0,所以每次二分的时候,把边权值减掉mid,之后bellmanford判负环即可 代码: #include <cstdio> #include <cst

UVA 11090 - Going in Cycle!!

二分+SPFA找负环 11090 - Going in Cycle!! Time limit: 3.000 seconds I I U P C 2 0 0 6 Problem G: Going in Cycle!! Input: standard input Output: standard output You are given a weighted directed graph with n vertices and m edges. Each cycle in the graph has

UVA - 11090 Going in Cycle!! (Bellman-Ford算法判负环)

Description I I U P C 2 0 06 Problem G: Going in Cycle!! Input: standard input Output: standard output You are given a weighted directed graph with n vertices and m edges. Each cycle in the graph has a weight, which equals to sum of its edges. There

UVA 11090 判负圈问题

题目链接http://vjudge.net/problem/viewProblem.action?id=34650 题目大意: 给定n个点m条边的加权有向图,求平均权值最小的回路.平均权值=路径权值之和/路径边数 我们可以通过找到他其中的最小和最大值,然后通过二分不断查找满足的点,然后尽可能的取到它的最大值,因为这里保留两位有效小数,所以设立 while(la-st>0.001)即可 找到一个满足的值是要建立在图上的每一条线段减去这个值后便能得到一个负圈,我们通常用spfa判负圈. 这个spfa

UVa 11090 Going in Cycle!! (Bellman_Ford)

题意:给定一个加权有向图,求平均权值最小的回路. 析:先十分答案,假设答案是 ans,那么有这么一个回路,w1+w2+w3+...+wk < k*ans,这样就是答案太大,然后移项可得,(w1-ans)+(w2-ans)+(w3-ans) + ..+(wk-ans) < 0,这样的话就判断是不是有负图就好了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio&g

UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)

题意:给定一个n个点m条边的带权有向图,求平均权值最小的回路的平均权值? 思路:首先,图中得有环的存在才有解,其次再解决这个最小平均权值为多少.一般这种就是二分猜平均权值了,因为环在哪也难以找出来,还有可能是一条边属于多个环.对于每个猜到的平均值,如果对应环的存在,那么这个环的每条边的权减去这个平均值之后,用spfa算法就能判断其是否有环的存在即可. 假设环上各边权值为:w1+w2+...+wk. 式子:w1+w2+...+wk<k*even   相当于   (w1-even)+(w2-even

UVA 11090 Going in Cycle!!(Bellman-Ford判断负圈)

题意:给定一个n个点m条边的加权有向图,求平均权值最小的回路. 思路:使用二分法求解,对于每一个枚举值mid,判断每条边权值减去mid后有无负圈即可. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<

UVa 11090 Going in Cycle!!【Bellman_Ford】

题意:给出n个点m条边的加权有向图,求平均值最小的回路 自己想的是用DFS找环(真是too young),在比较找到各个环的平均权值,可是代码实现不了,觉得又不太对 后来看书= =好巧妙的办法, 使用二分法求解,首先记录下来这m条边的最大权值ub 然后可以猜测一个mid,只需要判断是否存在平均值小于mid的回路 假设存在一个包含k条边的回路,回路上各条边的权值分别为w1,w,2,w3,----,wk 那么 w1+w2+w3+----+wk<k*mid 又因为联想到Bellman_Ford可以解决