判斷圖是否連通,可用dfs和bfs遍歷圖算法,注意點數目較多,又是稀疏圖的話,最后使用鄰接表的方法存儲。另外推薦采用的是並查集的方法。初始化時將每個節點看作一個集合,則每給出一條邊即把兩個集合合並。最后遍歷所有點,有幾個集合便有幾個連通分量,若只有一個集合說明圖連通。並查集方法通常情況下時間效率較高,還能判斷一個圖是否有回路,在kruskal算法中也可以使用。
(1)DFS判斷
int count = 0; void DFS(MGrap G. int i) { int j = 0; visited[i] = 1; count++; for(j=0; j<G.numVertexes; j++) { if(G.arc[i][j]==1 && !visited[j])//i和j有關系相鄰,並且j頂點沒有被訪問過 { DFS(G, j); } } }
從某一點出發開始DFS,到最后,只需要判斷最后count的值是否是全部的節點就可以,如果小於總節點數,則證明是不連通的,如果相等,則證明是連通的。
還可以訪問完一個節點,就將其刪除掉,可提高遍歷速度
void dfs(int s){ //遞歸深搜 vis[s]=true; for(int i=0;i<g[s].size();++i){ if(vis[g[s][i]]) g[s].erase(g[s].begin()+i);//刪除圖中已經遍歷過的點,可提高遍歷速度 else dfs(g[s][i]); } } bool judge(){ //判斷是否所有點已被遍歷過 for(int i=1;i<=n;++i) if(!vis[i]) return false; return true; }
(2)BFS判斷
void bfs(int s){ //用隊列廣搜 queue<int> q; q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); vis[x]=true; for(int i=0;i<g[x].size();++i){ if(vis[g[x][i]]) g[x].erase(g[x].begin()+i);//刪除圖中已經遍歷過的點,可提高遍歷速度 else q.push(g[x][i]); } } } bool judge(){ //判斷是否所有點已被遍歷過 for(int i=1;i<=n;++i) if(!vis[i]) return false; return true; }
同樣如果從某一個節點廣度搜完,有未訪問到的節點,那么該圖一定是不連通的。
(3)並查集
並查集一般用來判斷圖的連通性,還可以判斷圖中是否有回路。
如果並查集最后只有一個連通分量,證明此圖連通,否則此圖不連通
int set[1000005]; int find(int x){ return x==set[x]?x:(set[x]=find(set[x])); //遞歸查找集合的代表元素,含路徑壓縮。 } int main() { int n,m,i,x,y; scanf("%d%d",&n,&m); for(i=1;i<1000005;++i) //初始化個集合,數組值等於小標的點為根節點。 set[i]=i; for(i=0;i<m;++i){ int a,b; scanf("%d%d",&a,&b); int fx=find(a),fy=find(b); set[fx]=fy; //合並有邊相連的各個連通分量 } int cnt=0; for(i=1;i<=n;++i) //統計集合個數,即為連通分量個數,為一時,圖聯通。 if(set[i]==i) ++cnt; if(cnt==1) printf("yes\n"); else printf("no\n"); return 0; }