標籤:int ted 部落格 重複 images 訪問 visit using 否則
在一些經典演算法中,經常需要判斷一些圖是否具有環路,比如拓撲排序,需要在最初判斷該圖是否有環路,如有有環路,則無法找到最長的一條線,比如dijkstra演算法,每找到一條最短的邊,都要判斷找到的邊和現有的樹是否已經構成了環路。
因此,在這篇部落格,我們重點來說一個判斷圖是否有環的演算法。
首先我們介紹一個對於無向圖和有向圖通用的演算法,先講演算法思路:
1.統計各個圖中各個點的入度數(能夠到達這個點的點)。
2.然後找出入度數為0的點(無向圖找入度數為1的點)。
3.刪除入度數為0的點,將其邊也刪除。
4.重複2,直到所有點入度都為0,則為無環圖,如果找不到入度為0的點,則為有環圖。
該演算法的精髓在於對於一個環路(以有向圖為例),1->2,2->3,3->1,你會發現找不到一個入度為0的點,因此這個方法是可行的。
對於無向圖和有向圖來說,這個演算法是通用的。在這我唯寫了對於有向圖的判斷的演算法,具體的實現代碼如下:
#include<stdio.h>using namespace std;int graph[100][100];//用來儲存圖的數組bool isVisited[100];//判斷這個點是否已經刪除int main(){int n,e;while (scanf("%d",&n)!=EOF&&n!=0)//擷取點數{for(int i = 0;i<100;i++){isVisited[i] = false;for(int j = 0 ;j<100;j++){graph[i][j] = -1;//初始化資料,所有的邊都為-1,代表這兩個點之間不能聯通}}scanf("%d",&e);//擷取邊數for(int i = 0 ;i<e;i++)//構建圖{int a,b,c;scanf("%d %d %d",&a,&b,&c);graph[a-1][b-1] = c;}int isResult = true;for(int i = 0 ;i<n;i++)//進行n次迴圈,每次迴圈刪除一個入度為0的點,所以進行n次迴圈{for(int j = 0;j<n;j++)//遍曆所有的點,找入度為0的點{if(!isVisited[j])//判斷該點是否刪除{bool isCanVisited = true;//輔助變數,判斷這個點是否入度為0for(int k = 0;k<n ;k++){if(graph[k][j]!=-1){isCanVisited = false;//如果存在能夠訪問這個點的邊,則該點入度不為0}}if(isCanVisited)//如果該點入度為0,則下邊是刪除該點和刪除其相鄰邊{for(int k = 0 ;k<n;k++){graph[j][k] = -1;//刪除相鄰邊,即將值變為-1}isVisited[j] = true;//刪除該點}}}isResult = true;for(int j = 0 ;j<n;j++)//進行迴圈判斷當前多有點是否已經全部刪除,如果全部刪除,如果全部刪除則跳出,否則繼續迴圈{if(!isVisited[j]){isResult = false;}}if(isResult)break;}isResult = true;for(int i = 0 ;i<n;i++)//在所有點遍曆後,則通過這個迴圈來判斷是否所有點都已經刪除,如果全部刪除,則為無環圖,否則為有環圖{if(!isVisited[i])isResult = false;}if(isResult)printf("無環");if(!isResult)printf("有環");}return 0;}
實驗資料(第一行輸入n,e,n代表的是點數,e代表的是邊數,接下來e行代表具體的邊和其權值(權值暫時不用理會,是後續拓撲排序所有,因此當前暫時都為1)):
5 4
1 2 1
1 3 1
2 3 1
4 5 1
5 4
1 2 1
2 1 1
2 3 1
4 5 1
實驗結果:
演算法之判斷一個圖是否有環