如何判断图中是否有环,如果有输出每条环

 

题目】试写一个求有向图G中所有简单回路的算法
【思路】
方法一:

DFS搜索,直到搜索到已经遍历到的结点–>说明:找到了回路
判断该回路是否已经搜索到了(重复吗?)
不重复,放入结果集
方法二:

DFS搜索,只往结点编号大的结点搜索–>这样就不会重复寻找
搜索到和第一个位置上的结点相同–>搜索到了路径
找到后放入结果集
【测试数据】123456对应ABCDEF

方法一:用ALGraph举例

【结果】
在这里插入图片描述


【答案】

/*----------------------------------------------------------------
 |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);
    }
}

方法二:用MGraph举例

【结果】
在这里插入图片描述

/*----------------------------------------------------------------
 |7.30 求有向图中所有简单回路                                    |
 ----------------------------------------------------------------*/
int visit[MAX_VERTEX_NUM]; //访问标记
int p[MAX_VERTEX_NUM]; //暂存路径
int k;
int path[MAX_VERTEX_NUM+1][MAX_VERTEX_NUM+1]; //存储找到的路径
    // path[0][0] 存放路径的总个数
    // path[1][0] 存放第一条路径的长度 path[1][1]开始存放第一条的结点
void GetAllCycle_DFSUntil(MGraph G, int i) {
    int u,j;
    
    visit[i] = 1; //标记i已访问
    
    //用u遍历i的邻边
    for (u=0; u<G.vexnum; u++) {
        if (G.arcs[i][u].adj==0) continue; //i到u没有边:退出
        
        // u>p[1] --> i的邻边>路径的第一个结点编号 --> 只往结点号大的地方走,不要往回走 --> 往回走就会找重复的
        if (u>p[1] && visit[u]==0) {
            p[++k] = u; //记到路径上
            GetAllCycle_DFSUntil(G, u); //往u继续走
        }
        // i的邻边u==路径的第一个结点 --> 找到了一条回路
        if (u==p[1]) {
            path[0][0]++; //总路径的个数
            path[ path[0][0] ][0] = k; // 路径长度
            for (j=1; j<=k; j++) //将求得的路径存入路径数组
                path[ path[0][0] ][j] = p[j]; //回路的终点即起点,不存入数组
        }
    }

    visit[ p[k] ] = 0; //返回上一个顶点
    k--;
}
void GetAllCycle(MGraph G) {
    int i,j;

    // path初始化
    for (i=0; i<MAX_VERTEX_NUM; i++) {
        for (j=0; j<MAX_VERTEX_NUM; j++)
            path[i][j]=0;
    }
    // 访问状态初始化:初始为WHITE
    for (i=0; i<=G.vexnum; i++) visit[i]=0;
    // 开始找
    for (i=0; i<=G.vexnum; i++) {
        k=1; //路径的第一个结点
        p[k]=i; //第一个结点的编号为i
        GetAllCycle_DFSUntil(G, i);
    }
}

方法一的完整代码

【完整代码】

#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;
}

方法二的完整代码

#include<stdio.h>
#include<stdlib.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

typedef char VertexType;//点类型
typedef int VRType; //边类型
void Visit(VertexType e) {
    printf("%c", e);
}
#define maxSize 20

#define MAX_VERTEX_NUM 20
typedef enum{UDG, DG} GraphKind;
typedef struct ArcCell{
    VRType adj;
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct{
    VertexType vexs[MAX_VERTEX_NUM]; //顶点
    AdjMatrix arcs; //弧的信息
    int vexnum,arcnum;
    GraphKind kind;
}MGraph;

Status CreateG_MG(MGraph *pG) {
    int i,j,w;
    char tmp[maxSize];
    scanf("%d", &i); if (i<0) return ERROR;
    pG->vexnum = i;
    scanf("%d", &i); if (i<0) return ERROR;
    pG->arcnum = i;
    scanf("%s", tmp);
    for (i=0; i<pG->vexnum; i++) pG->vexs[i]=tmp[i];
    for (i=0; i<pG->vexnum; i++) {
        for (j=0; j<pG->vexnum; j++) {
            scanf("%d", &w);
            pG->arcs[i][j].adj = w;
        }
    }
    return OK;
}

/*----------------------------------------------------------------
 |7.30 求有向图中所有简单回路                                    |
 ----------------------------------------------------------------*/
int visit[MAX_VERTEX_NUM]; //访问标记
int p[MAX_VERTEX_NUM]; //暂存路径
int k;
int path[MAX_VERTEX_NUM+1][MAX_VERTEX_NUM+1]; //存储找到的路径
    // path[0][0] 存放路径的总个数
    // path[1][0] 存放第一条路径的长度 path[1][1]开始存放第一条的结点
void GetAllCycle_DFSUntil(MGraph G, int i) {
    int u,j;
    
    visit[i] = 1; //标记i已访问
    
    //用u遍历i的邻边
    for (u=0; u<G.vexnum; u++) {
        if (G.arcs[i][u].adj==0) continue; //i到u没有边:退出
        
        // u>p[1] --> i的邻边>路径的第一个结点编号 --> 只往结点号大的地方走,不要往回走 --> 往回走就会找重复的
        if (u>p[1] && visit[u]==0) {
            p[++k] = u; //记到路径上
            GetAllCycle_DFSUntil(G, u); //往u继续走
        }
        // i的邻边u==路径的第一个结点 --> 找到了一条回路
        if (u==p[1]) {
            path[0][0]++; //总路径的个数
            path[ path[0][0] ][0] = k; // 路径长度
            for (j=1; j<=k; j++) //将求得的路径存入路径数组
                path[ path[0][0] ][j] = p[j]; //回路的终点即起点,不存入数组
        }
    }

    visit[ p[k] ] = 0; //返回上一个顶点
    k--;
}
void GetAllCycle(MGraph G) {
    int i,j;

    // path初始化
    for (i=0; i<MAX_VERTEX_NUM; i++) {
        for (j=0; j<MAX_VERTEX_NUM; j++)
            path[i][j]=0;
    }
    // 访问状态初始化:初始为WHITE
    for (i=0; i<=G.vexnum; i++) visit[i]=0;
    // 开始找
    for (i=0; i<=G.vexnum; i++) {
        k=1; //路径的第一个结点
        p[k]=i; //第一个结点的编号为i
        GetAllCycle_DFSUntil(G, i);
    }
}

int main() {
/*
6
11
ABCDEF
0 0 0 0 0 0
1 0 0 1 0 0
0 1 0 0 0 1
0 0 1 0 1 1
1 0 0 0 0 0
1 1 0 0 1 0
*/
    MGraph G;
    int pathsNum; //路径的个数
    int pathlen; //该路径的长度
    int i,j;
    int node;
    G.kind = DG;
    CreateG_MG(&G);

    GetAllCycle(G);

    //输出所有回路
    pathsNum = path[0][0];
    for (i=1; i<=pathsNum; i++) { //一共有i条回路
        pathlen = path[i][0]; //第i条路径有pathlen个结点
        for (j=1; j<=pathlen; j++) {
            node = path[i][j];
            Visit(G.vexs[node]);
        }
        printf("\n");
    }
    return 0;
}
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值