UVA 558 SPFA 判断负环

这个承认自己没看懂题目,一开始以为题意是形成环路之后走一圈不会产生负值就输出,原来就是判断负环,用SPFA很好用,运用队列,在判断负环的时候,用一个数组专门保存某个点的访问次数,超过了N次即可断定有负环(其实我觉得=N次了就可以断定了,当然这样是保险起见)。。。。别人还有用SPFA+DFS做的,还效率相当高,我还没怎么弄明白是怎么回事。。。还有,我突然想到讲最短路的时候说迪杰斯特拉不能用于有负权的图,这是为什么。。我还没想明白,先去睡觉吧。。。。

 

关于dijstla为什么不能有负权,昨晚躺下之后就想明白了,dijstla最大特性在于其把当前d值最小的点给灰化了,下次不用再访问了,而负权如果存在,将使得已经发生灰化的点,d值会变小,这样就不得不取消灰化,但一旦取消,dijstla就永远无法走到终点,(将一直在d值最小的那个点徘徊),因此spfa通过用队列把d值发生变化的点加进去,因而解决了这个问题这只是题外话,不用说太多

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int u[2010],v[2010],w[2010],next[2010],first[1010];
int d[1010],vis[1010],num[1010];
int n,m,cnt,flag;
void addedge(int a,int b,int c)
{
    u[cnt]=a;
    v[cnt]=b;
    w[cnt]=c;
    next[cnt]=first[a];
    first[a]=cnt++;
}
void spfa()
{
    int i,j;
    flag=0;
    for (i=0;i<=n;i++)
        d[i]=(1<<30);
    memset(vis,0,sizeof vis);
    memset(num,0,sizeof num);
    d[0]=0;
    queue <int> q;
    q.push(0);
    vis[0]=1;
    while (!q.empty())
    {
        int t=q.front();
        q.pop();
        vis[t]=0;
        for (j=first[t];j>=0;j=next[j])
        {
            int newnode=v[j];
            num[newnode]++;
            if (num[newnode]>n){
                   flag=1;
                    return;
            }
            if (d[newnode]>d[t]+w[j])
            {

                d[newnode]=d[t]+w[j];
                //cout<<newnode<<" "<<d[newnode]<<endl;
                if (!vis[newnode]){
                    q.push(newnode);
                    vis[newnode]=1;
             }
            }
        }
    }
}
int main()
{
    int t,i,j;
    scanf("%d",&t);
    while (t--)
    {
        cnt=0;
        memset(first,-1,sizeof first);
        scanf("%d%d",&n,&m);
        int a,b,c;
        for (i=1;i<=m;i++){

          scanf("%d%d%d",&a,&b,&c);
          addedge(a,b,c);
        }
        spfa();
        if (!flag)
            puts("not possible");
        else
            puts("possible");
    }
    return 0;
}

 

posted @ 2014-01-13 22:48  KRisen  阅读(408)  评论(0编辑  收藏  举报