zoukankan      html  css  js  c++  java
  • [poj3259]Wormholes(spfa判负环)

    题意:有向图判负环。

    解题关键:spfa算法+hash判负圈。

    spfa判断负环:若一个点入队次数大于节点数,则存在负环。 

    两点间如果有最短路,那么每个结点最多经过一次,这条路不超过$n-1$条边。”

    如果一个结点经过了两次,那么我们走了一个圈。如果这个圈的权为正,显然不划算;如果是负圈,那么最短路不存在;如果是零圈,去掉不影响最优值。

    也就是说,每个点最多入队$n-1$次,可以想象一下,左边$n-1$个节点全部指向右边一个节点,遍历的顺序恰好与边权顺序相反。

    负圈是指圈上的总和小于0

    实际只要大于$n-1$次,即可判断。上述判断条件仅为充分条件。

    1至于为什么是$>n$是因为对于一个节点时候 如果还是$>n-1$那么任意一个单节点的图会被判定为存在负环 综合考虑取$>n$

    入队vis=true,出队vis=false

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<iostream>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxm=11111;
    const int maxn=500;
    int head[maxn],tot,n,m,num[maxn],w;
    struct edge{
        int to;
        int w;
        int nxt;
    }e[maxm];
    void add_edge(int u,int v,int w){
        e[tot].w=w;
        e[tot].to=v;
        e[tot].nxt=head[u];
        head[u]=tot++;
    }
    
    bool vis[maxn];
    queue<int>que;//队列是点的队列 
    int d[maxn];
    bool spfa(int s){
        memset(num,0,sizeof num);
        fill(d+1,d+n+1,inf);
        memset(vis,0,sizeof vis);
        while(!que.empty()) que.pop();
        que.push(s);
        vis[s]=true;
        d[s]=0;
        while (!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=false;
            for (int i=head[u];i!=-1;i=e[i].nxt){
                int v=e[i].to;
                int w=e[i].w;
                if (d[v]>d[u]+w){
                    d[v]=d[u]+w;
                    if (!vis[v]){
                        vis[v]=true;
                        que.push(v);//hash一下,可判断是否存在负环 
                        num[v]++;
                        if(num[v]>n) return true;
                    }
                }
            }
        }
        return false;
    }
    int main(){
        ios::sync_with_stdio(0);
        int a,b,c,T;
        cin>>T;
        while(T--){
            tot=0;
            memset(head,-1,sizeof head);
            cin>>n>>m>>w;
            for(int i=0;i<m;i++){//注意为双向边 
                cin>>a>>b>>c;
                add_edge(a,b,c);
                add_edge(b,a,c);
            }
            for(int i=0;i<w;i++){
                cin>>a>>b>>c;
                add_edge(a,b,-c);
            }
            if(spfa()) puts("YES");
            else puts("NO");
        }
        return 0;
    }
  • 相关阅读:
    解决vs 编译的bug“请检查是否是磁盘空间不足、路径无效或权限不够”
    lua 使用正则表达式分割字符串
    cocos2dx通过ndk编译c++库
    通过luac编译lua脚本
    redis的一个bug
    将文件转成16进制过程
    fiddler 模拟发送post请求
    cocostudio的bug(1)
    Eclipse+Tomcat搭建jsp服务器
    iOS本地推送与远程推送
  • 原文地址:https://www.cnblogs.com/elpsycongroo/p/7896936.html
Copyright © 2011-2022 走看看