UVA11090 Going in Cycle (二分+判负环)

二分法+spfa判负环。如果存在一个环sum(wi)<k*x,i=0,1,2...,k,那么每条边减去x以后会形成负环。因此可用spfa来判负环。

一般spfa判负环dfs最快,用stack次之,queue最慢,因为一个负环中被更新的点是连续的。

一开始不知到图的连通情况,所以把所有点都入栈更新。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 51;

struct Edge
{
    int v,nxt;
    double w;
};
vector<Edge> edges;
int head[maxn];
#define PB push_back
void addEdge(int u,int v,double w)
{
    edges.PB({v,head[u],w});
    head[u] = edges.size()-1;
}

bool vis[maxn];
double d[maxn];
int cnt[maxn];

bool spfa(int n)
{
    stack<int>S;
    memset(vis,0,sizeof(vis));
    memset(cnt,0,sizeof(cnt));
    for(int i = 0; i < n; i++) { vis[i] = true; d[i] = 0.; S.push(i); }
    while(S.size()){
        int u = S.top(); S.pop();
        vis[u] = false;
        for(int i = head[u]; ~i; i = edges[i].nxt){
            Edge &e = edges[i];
            if(d[e.v]>d[u]+e.w){
                d[e.v] = d[u]+e.w;
                if(!vis[e.v]){
                    S.push(e.v); vis[e.v] = true;
                    if(++cnt[e.v] > n) return true;
                }
            }
        }
    }
    return false;
}

bool P(double x,int n)
{
    for(int i = 0; i < (int)edges.size(); i++) edges[i].w -= x;
    bool ret = spfa(n);
    for(int i = 0; i < (int)edges.size(); i++) edges[i].w += x;
    return ret;
}

void init()
{
    memset(head,-1,sizeof(head));
    edges.clear();
}

const double eps = 1e-4;

int main()
{
    //freopen("in.txt","r",stdin);
    int T;cin>>T;
    int kas = 0;
    while(T--){
        init();
        int n,m; scanf("%d%d",&n,&m);
        double l = 0, r = 0;
        while(m--){
            int u,v; double w; scanf("%d%d%lf",&u,&v,&w);
            addEdge(u-1,v-1,w);
            r = max(r,w);
        }
        printf("Case #%d: ",++kas);
        if(!P(r+1,n)) { puts("No cycle found."); continue; }
        for(double mid; r-l>eps; P(mid,n)?r=mid:l=mid) mid = l+(r-l)/2;
        printf("%.2lf
",l);
    }
    return 0;
}

dfs+判负环

bool vis[maxn];
double d[maxn];
bool dfs(int u)
{
    vis[u] = true;
    for(int i = head[u]; ~i ; i = edges[i].nxt){
        Edge &e = edges[i];
        if(d[e.v] > d[u]+e.w){
            d[e.v] = d[u]+e.w;
            if(!vis[e.v]){
                if(dfs(e.v)) return true;
            }else  return true;
        }
    }
    vis[u] = false;
    return false;
}

调用
for(int u = 0; u < n; u++){
        if(dfs(u)) { ret = true; break; }
    }
原文地址:https://www.cnblogs.com/jerryRey/p/4781343.html