關於判環

關於有向圖的判環

1.只有正(負)邊權

拓撲排序一遍就好了

記住,圖不一定是聯通時,一定要把每個入度爲零的節點跑一遍!!!

核心代碼如下:

int in[N],timeq=0,n,m;//timeq 時間戳 
int vis[N];//標記數組 
inline bool dfs(int u){//u 當前節點 
    bool flag=false;//flag 標記 
    for(int i=head[u];i;i=e[i].next){//領接表遍歷圖 
        int v=e[i].to;
        if(timeq==vis[v]) return true;//當前邊是返祖邊,則有環 
        else if(vis[v]) return false;//上次遍歷過了且不是這次遍歷產生的,一定沒有環 
        flag=dfs(v);//遍歷 
        if(flag) return true;
    }
    return false;
}
int main(){
    scanf("%d%d",&n,&m);//n 節點數  m 邊數 
    for(int i=1;i<=m;i++){
        int x,y,val;
        scanf("%d%d%d",&x,&y,&val);// x->y的邊權值爲val 
        add(x,y,val);//鄰接表存邊 
        in[y]++;//統計入度 
    }
    for(int i=1;i<=n;i++)//順次訪問入度爲0的節點 
        if(!in[i]){
            vis[i]=++timeq;//標記訪問次數
            if(dfs(i)){//遍歷 
                printf("Yes");//有環 
                return 0;
            }
        }
    printf("No");//無環 
} 

2.既有正權邊又有負權邊

這時,我們就要用SPFA(此處所講的是dfs版),其實可以用堆優化,但是作者懶,在這不想寫

其實也麼什麼好講的,主要看毒瘤出題人有沒有給重邊和自環代碼實現

下面的代碼包含處理重邊和自環的情況:

#include<stdio.h>
#define N 2007
using namespace std;
#define INF 0x3f3f3f3f
struct E{
    int next,to,dis;
}e[N<<2];
int head[N],cnt=0,n,m,dis[N],st;
bool vis[N];
inline void read(int &x){
    x=0;int flag=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') flag=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
    x*=flag;
}
inline void add(int id,int to,int dis){//存圖 
    cnt++;
    e[cnt].next=head[id];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[id]=cnt;
}
inline bool dfs(int u){
    vis[u]=true;//標記已訪問過 
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;
        if(u==v&&e[i].dis<0) return true;//如果是自環且dis小於0,此環定是負環 
        if(dis[v]>dis[u]+e[i].dis){//更新 
            if(vis[v]) return true;//如果訪問過且這次又更新了,一定有負環 
            dis[v]=dis[u]+e[i].dis;
            if(dfs(v)) return true;//往下遍歷 
        }
    }
    vis[u]=false;//回溯 
    return false;//返回沒有環 
}
int main(){
    read(n);read(m);read(st);//st 源點 
    for(int i=1;i<=n;i++) 
        dis[i]=INF,vis[i]=false;//初始化 dis 到源點的最短路距離 vis 標記數組
    for(int i=1;i<=m;i++){
        int x,y,dis;
        read(x);read(y);read(dis);
        add(x,y,dis);
    }
    dis[st]=0;//初始源點到自身距離爲0 
    bool flag=dfs(st);
    if(flag) printf("Yes\n");
    else printf("No\n");
}

 

關於無向圖的判環

無向圖就更簡單了

直接遍歷一遍,如果遇到返祖邊則判斷一下當前記錄的dis[u]+e[i].dis是否爲負

如果是,則一定有負環,否則當前沒有負環,回溯

其餘情況直接往下遍歷就是了,沒有過多技巧,這裏就不再贅述

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章