寻找有向图中所有的环

Billy_wan 2016-03-15 09:35:17
如题,
现在有一个想法是:
一个节点可能有四个状态: 0 , 1 , 2 , -1
0代表该节点未被访问,1代表该节点正在被访问,2表示该节点已经被访问且已经在一个环中,-1表示该节点已经被访问过且没有处于任何一个环中。
利用深度遍历有向图。

不知道这种算法是不是有缺陷,不知道咋论证。自己实现了一下没成功,总是出现各种问题,代码如下(不准确,未完成找环功能):
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;


#define maxNum 10 //定义邻接举证的最大定点数

#define maxCycle 10


int temp[maxNum];//用于环路共用路径的暂时存储

typedef struct cycle_package
{
int visited[maxNum];//通过visited数组来标记这个顶点是否被访问过,0表示未被访问,1表示被访问
int cycle[maxCycle][maxNum];//存储找到的环路

int num_cycle ;//用于环路数量的增加

};

//图的邻接矩阵表示结构
typedef struct
{
char v[maxNum];//图的顶点信息
int e[maxNum][maxNum];//图的边信息
int vNum;//顶点个数
int eNum;//边的个数
}graph;

graph *g;

void createGraph(graph *g);//创建图g
void DFS(cycle_package *cp,graph *g);//深度优先遍历图g
void Print(cycle_package *cp,int head,int pre,int next,int num_dot);//保存环路径中的结点
void Visit(cycle_package *cp,int begin,int head,int pre_i,int j,int order=0);//沿visited值为2的搜索,不能回头,不能为环头
void Visit(cycle_package *cp,int begin,int head,int pre_i,int j,int order)
{
struct list
{
int order;
int positon;
int mark;
};
int temp_counter = 0;
temp[order] = j;
list visited_c[maxNum];
int v_c_counter = 0;
int go_mark = 0;//默认没有-1结点
for (int i = 0;i<g->vNum;i++)//此循环与下一循环是为了将visited数组中的标志排序,优先访问-1结点
{
if (cp->visited[i]==-1)
{
visited_c[v_c_counter].mark= -1;
visited_c[v_c_counter].positon = i;
v_c_counter++;
//head_mark = 1;
}

}

for (int i = 0;i<g->vNum;i++)
{
if (cp->visited[i]==2)
{
visited_c[v_c_counter].mark=2;
visited_c[v_c_counter].positon = i;
v_c_counter++;
}

}


for (int i = 0;i<v_c_counter;i++)
{
/*在此循环中出现了这样的问题,按照标志=-1的结点走完之后,又会走标志等于2的路径,导致进入一个无限的循环*/

if(g->e[j][visited_c[i].positon]!=0&&visited_c[i].mark==-1&&go_mark == 0)
{

int temp_i;
for (temp_i = 1;temp_i<=(order+1);temp_i++)
{
cp->cycle[cp->num_cycle][temp_i] = temp[temp_i-1];

}
int temp_num = temp[order];//temp[order]不能直接传给print()
// cp->visited[visited_c[i].positon] = 2;
Print(cp,temp_num,j,visited_c[i].positon,temp_i);
cp->visited[begin] = 2;
cp->cycle[cp->num_cycle][0] = begin;
go_mark = 1;
cp->num_cycle++;
order = 0;
}
else if (visited_c[i].positon!=head&&visited_c[i].positon!=pre_i&&visited_c[i].mark==2&&g->e[j][visited_c[i].positon]!=0&&go_mark== 0)
{

Visit(cp,begin,head,j,visited_c[i].positon,order+1);
}



}
}


void Print(cycle_package *cp,int head,int pre,int next,int num_dot)//num_dot记录环路中的点数量
//有半途指向2的情况!!!
{
int temp_n = num_dot;

int go_mark = 0;
if (next != head)
{


for (int k = 0;k<g->vNum;k++)
{
if (g->e[next][k]!= 0&&(cp->visited[k] == -1)&&go_mark == 0)
{
//cp->viitesd[next] = 2;
cp->visited[next] = 2;
cp->cycle[cp->num_cycle][num_dot] = next;
temp_n++;
Print(cp,head,next,k,temp_n);
go_mark = 1;
}
else if(g->e[next][k]!=0&&(cp->visited[k]==2)&&k!=pre)
{
cp->visited[next] = 2;
cp->cycle[cp->num_cycle][num_dot] = next;
temp_n++;
Visit(cp,next,k,-1,k);
}
}

}
//else {cp->visited[next] = 2;
// cp->cycle[cp->num_cycle][num_dot] = next;
// temp_n++;}

}


void dfs(cycle_package *cp,graph *g,int cur_point)
{
//cout<<"顶点"<<g->v[i]<<"已经被访问"<<endl;
// cout<<"顶点"<<i<<"已经被访问"<<endl;

cp->visited[cur_point]=-1;//标记顶点i被访问
for(int next_point=0;next_point<g->vNum;next_point++)
{
if(g->e[cur_point][next_point]!=0&&cp->visited[next_point]==0)
{dfs(cp,g,next_point); }
else if(g->e[cur_point][next_point]!=0&&cp->visited[next_point]==-1&&next_point!=cur_point)
{

Print(cp,cur_point,cur_point,next_point,1);
cp->visited[cur_point] = 2;
cp->cycle[cp->num_cycle][0] = cur_point;

cp->num_cycle++;

}
else if (g->e[cur_point][next_point]!=0&&cp->visited[next_point]==2)
{
Visit(cp,cur_point,next_point,-1,next_point);
}

}
if(cp->visited[cur_point]!=2)
cp->visited[cur_point] = 1;
}

void DFS(cycle_package *cp,graph *g)
{
int i;
//初始化visited数组,表示一开始所有顶点都未被访问过
for(i=0;i<g->vNum;i++)
cp->visited[i]=0;
//深度优先搜索
for(i=0;i<g->vNum;i++)
if(cp->visited[i]==0)//如果这个顶点未被访问过,则从i顶点出发进行深度优先遍历
dfs(cp,g,i);
int k = 0;
cout <<k<<endl;
}

void createGraph(graph *g)//创建图g
{
cout<<"正在创建无向图..."<<endl;
cout<<"请输入顶点个数vNum:";
cin>>g->vNum;
cout<<"请输入边的个数eNum:";
cin>>g->eNum;
int i,j;

//输入顶点信息
//cout<<"请输入顶点信息:"<<endl;
//for(i=0;i<g->vNum;i++)
// cin>>g->v[i];

//初始画图g
for(i=0;i<g->vNum;i++)
for(j=0;j<g->vNum;j++)
g->e[i][j]=0;

//输入边的情况
cout<<"请输入边的头和尾"<<endl;
for(int k=0;k<g->eNum;k++)
{
cin>>i>>j;
g->e[i][j]=1;

}
}

int main()
{
cycle_package *cy;
cy = (cycle_package *)malloc(sizeof(cycle_package));
cy->num_cycle = 0;
g=(graph*)malloc(sizeof(graph));
createGraph(g);
DFS(cy,g);
int i;
cin>>i;
system("pause");
return 0;
}
...全文
2378 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
不朽的图灵 2018-06-30
  • 打赏
  • 举报
回复
用DFS可以找到所有的环。
import java.util.*;

public class GetAllCyclesForDirectedGraph{
static Set<Integer> searched=new HashSet<>();
static Set<List<Integer>> allCircles = new HashSet<>();

public static void main(String[] args) {
int n=9;
int[][] e={ {0, 1, 0, 0, 0, 1, 0, 0, 0},
{0, 0, 1, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0, 0, 0},
{0, 0, 1, 0, 1, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 0, 0, 0, 0, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0, 0, 1, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 1},
{0, 0, 0, 0, 1, 0, 0, 0, 0}};
for(int i=0;i<n;i++){
if(searched.contains(i))
continue;
List<Integer> trace =new ArrayList<>();
findCycle(i,e);
}

for(List<Integer> list:allCircles)
System.out.println("circle: "+list);
}


static void findCycle(int v, int[][]e){
int j=trace.indexOf(v);
if(j!=-1) {31 List<Integer> circle=new ArrayList<>();
while(j<trace.size()) {35 circle.add(trace.get(j));
j++;
}
Collections.sort(circle);
allCircles.add(circle);
return;
}


trace.add(v);
for(int i=0;i<e.length;i++) {
if(e[v][i]==1){
searched.add(i);
findCycle(i,e);
}
}
trace.remove(trace.size()-1);
}

}
Billy_wan 2016-03-15
  • 打赏
  • 举报
回复
我借鉴了这篇文章上的算法: http://blog.csdn.net/sunmenggmail/article/details/7324646

590

社区成员

发帖
与我相关
我的任务
社区描述
提出问题
其他 技术论坛(原bbs)
社区管理员
  • community_281
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧