1. 程式人生 > >[圖] 7.30 求有向圖中所有簡單迴路-鄰接表-DFS

[圖] 7.30 求有向圖中所有簡單迴路-鄰接表-DFS

題目來源:嚴蔚敏《資料結構》C語言版本習題冊 7.30

【題目】試寫一個求有向圖G中所有簡單迴路的演算法

【測試資料】123456對應ABCDEF 在這裡插入圖片描述

【結果】 在這裡插入圖片描述

【答案】

/*----------------------------------------------------------------
 |7.30 求有向圖中所有簡單迴路                                    |
 ----------------------------------------------------------------*/
VertexType cycles[maxSize]
[MAX_VERTEX_NUM+1]; //存放所有迴路 int path[MAX_VERTEX_NUM+1]; //路徑,前面定義過 int visit[MAX_VERTEX_NUM]; //訪問標記,前面定義過 int pathnum=0; //已發現的路徑個數,前面已經定義過 Status ExistCycle(ALGraph G, int start, int end) { // [start,end) int i,j,k,e; int len; int flag=0; len = end-start; for (i=0; i<pathnum; i++) { if (strlen(cycles[
i])==len) { //長度一樣 //[start,end) ?= cycles[i]-->判斷兩個迴路是否相同 flag=0; //找到了0個一樣的 for (j=start; j<end; j++) { e = path[j]; //在cycles[i]中找e for (k=0; cycles[i][k]!='\0'; k++) { if (cycles[i][k]==G.vers[e].data) flag++; //找到了 } } if (flag==len) return TRUE; //找到了len一樣的元素-->完全相同
} } return FALSE; //不存在 } void FindAllCycle(ALGraph G, int v, int k) { ArcNode *p; int i,j; int start,nextadj; visit[v]=1; path[k]=v; // 從v的鄰邊開始走 for (p=G.vers[v].firstarc; p; p=p->next) { nextadj = p->adjV; //下一個結點 if (visit[nextadj]) { //已經訪問過了-->找到了迴路 //找到這條迴路的起始點 for (i=0; i<k; i++) { if (path[i]==nextadj) { start=i; } } if (!ExistCycle(G, start, k+1)) { //這個迴路沒有重複 for (i=start, j=0; i<=k; i++,j++) { cycles[pathnum][j] = G.vers[ path[i] ].data; } cycles[pathnum][j]='\0'; pathnum++; } } else { //沒有訪問過,繼續訪問 FindAllCycle(G, nextadj, k+1); } } // 回溯 visit[v]=0; path[k]=0; } void GetAllCycle(ALGraph G) { int i; for (i=0; i<G.vernum; i++) visit[i]=0; //訪問標記初始化 pathnum=0; //路徑個數初始化 for (i=0; i<G.vernum; i++) { if (visit[i]==0) FindAllCycle(G, i, 0); } }

【完整程式碼】

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#ifndef BASE
#define BASE
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int bool;
#endif

#define VertexType char //點型別
#define VRType int //邊型別
#define maxSize 100
void Visit(VertexType e) {
	printf("%c", e);
}

#define MAX_VERTEX_NUM 20
typedef enum{DG, UDG} GraphKind;
typedef struct ArcNode{
	int adjV; //邊指向的頂點
	VRType weight; //權重
	struct ArcNode *next;
}ArcNode; //邊
typedef struct VNode{
	VertexType data;
	ArcNode *firstarc;
}VNode, AdjList[MAX_VERTEX_NUM]; //頂點
typedef struct{
	GraphKind kind;
	int vernum,arcnum;
	AdjList vers; 
}ALGraph;


/*------------------------
 |7.14 建立有向圖的鄰接表|
 ------------------------*/
Status InitGraph_AL(ALGraph *pG) { //初始化
	int i;
	pG->arcnum = 0;
	pG->vernum = 0;
	for (i=0; i<MAX_VERTEX_NUM; ++i)
		pG->vers[i].firstarc = NULL; //VC++6.0中指標初始化為0xcccccccc
	return OK;
}
int LocateVex_AL(ALGraph G, VertexType e) { //定位值為e的元素下標
	int i;
	for (i=0; i<G.vernum; ++i) {
		if (G.vers[i].data == e) {
			return i;
		}
	}
	return -1;
}
Status CreateDG_AL(ALGraph *pG) { //建立有向圖的鄰接表
	//輸入規則:頂點數目->弧的數目->各頂點的資訊->各條弧的資訊
	int i,a,b;
	char tmp[MAX_VERTEX_NUM];
	char h,t;
	ArcNode *p, *q;

	InitGraph_AL(pG); //VC++6.0中指標初始化為0xcccccccc,如果不將指標初始化為NULL,會出錯
	//圖的型別
	pG->kind = DG;
	//頂點數目
	scanf("%d", &i); if (i<0) return ERROR;
	pG->vernum = i;
	//弧的數目
	scanf("%d", &i); if (i<0) return ERROR;
	pG->arcnum = i;
	//各頂點資訊
	scanf("%s", tmp);
	for (i=0; i<pG->vernum; ++i) pG->vers[i].data=tmp[i];
	//弧的資訊
	for (i=0; i<pG->arcnum; ++i) {
		scanf("%s", tmp);
		h = tmp[0]; t = tmp[2];
		a = LocateVex_AL(*pG, h);
		b = LocateVex_AL(*pG, t);
		if (a<0 || b<0) return ERROR;
		p = (ArcNode *)malloc(sizeof(ArcNode)); if (!p) exit(OVERFLOW);
		p->adjV=b;p->next=NULL;
		if (pG->vers[a].firstarc) { //已經有邊了
			for (q = pG->vers[a].firstarc; q->next; q=q->next) ; //找到最後一條
			q->next = p;
		} else { //第一條邊
			pG->vers[a].firstarc = p;
		}
	}
	return OK;
}

/*----------------------------------------------------------------
 |7.30 求有向圖中所有簡單迴路                                    |
 ----------------------------------------------------------------*/
VertexType cycles[maxSize][MAX_VERTEX_NUM+1]; //存放所有迴路
int path[MAX_VERTEX_NUM+1]; //路徑,前面定義過
int visit[MAX_VERTEX_NUM]; //訪問標記,前面定義過
int pathnum=0; //已發現的路徑個數,前面已經定義過
Status ExistCycle(ALGraph G, int start, int end) { // [start,end)
	int i,j,k,e;
	int len;
	int flag=0;

	len = end-start;
	for (i=0; i<pathnum; i++) {
		if (strlen(cycles[i])==len) { //長度一樣
			//[start,end) ?= cycles[i]-->判斷兩個迴路是否相同
			flag=0; //找到了0個一樣的
			for (j=start; j<end; j++) {
				e = path[j];
				//在cycles[i]中找e
				for (k=0; cycles[i][k]!='\0'; k++) {
					if (cycles[i][k]==G.vers[e].data) flag++; //找到了
				}
			}
			if (flag==len) return TRUE; //找到了len一樣的元素-->完全相同
		}
	}
	return FALSE; //不存在
}
void FindAllCycle(ALGraph G, int v, int k) {
	ArcNode *p;
	int i,j;
	int start,nextadj;
	visit[v]=1;
	path[k]=v;
	// 從v的鄰邊開始走
	for (p=G.vers[v].firstarc; p; p=p->next) {
		nextadj = p->adjV; //下一個結點
		if (visit[nextadj]) { //已經訪問過了-->找到了迴路
			//找到這條迴路的起始點
			for (i=0; i<k; i++) {
				if (path[i]==nextadj) {
					start=i;
				}
			}
			if (!ExistCycle(G, start, k+1)) { //這個迴路沒有重複
				for (i=start, j=0; i<=k; i++,j++) {
					cycles[pathnum][j] = G.vers[ path[i] ].data;
				}
				cycles[pathnum][j]='\0';
				pathnum++;
			}
		} else { //沒有訪問過,繼續訪問
			FindAllCycle(G, nextadj, k+1);
		}
	}
	// 回溯
	visit[v]=0;
	path[k]=0;
}
void GetAllCycle(ALGraph G) {
	int i;
	for (i=0; i<G.vernum; i++) visit[i]=0; //訪問標記初始化
	pathnum=0; //路徑個數初始化
	for (i=0; i<G.vernum; i++) {
		if (visit[i]==0) FindAllCycle(G, i, 0);
	}
}



int main() {
/*7.30
6
11
ABCDEF
B,A
B,D
C,B
C,F
D,C
D,E
D,F
E,A
F,A
F,B
F,E
*/
	int i;
	ALGraph G;

	CreateDG_AL(&G);
	GetAllCycle(G);
	printf("發現%d條簡單迴路\n", pathnum);
	for (i=0; i<pathnum; i++) {
		printf("%s\n", cycles[i]);
	}
	
	return 0;
}