[圖] 7.30 求有向圖中所有簡單迴路-鄰接表-DFS
阿新 • • 發佈:2018-12-14
題目來源:嚴蔚敏《資料結構》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;
}