求图的简单路径和回路
下面是用邻接表存储无向图,然后输出图中指定顶点间的指定长度的简单路径,
简单路径就是路径中的顶点不重复,
还有一个就是求出图中经过某顶点的回路,
都是对图的遍历算法的应用,
主要是深度优先的遍历,
加上简单的回溯。
下面是代码
- //文件"graph.h"
2.
3. #include <iostream>
4. #include <string> 求图的简单路径和回路
下面是用邻接表存储无向图,然后输出图中指定顶点间的指定长度的简单路径,
简单路径就是路径中的顶点不重复,
还有一个就是求出图中经过某顶点的回路,
都是对图的遍历算法的应用,
主要是深度优先的遍历,
加上简单的回溯。
下面是代码
- //文件"graph.h"
2.
3. #include <iostream>
4. #include <string>
5. #include <queue>
6. using namespace std;
7. bool visited[20];
8. int path[20];
9. struct ArcNode
10. {
11. int adjvex;
12. ArcNode *nextarc;
13. };
14.
15. struct VexNode
16. {
17. string data;
18. ArcNode *firstarc;
19. };
20.
21. class NDGraph
22. {
23. private:
24. VexNode vertices[20];
25. int vexnum;
26. int arcnum;
27. public:
28. NDGraph()
29. {
30. vexnum=0;
31. arcnum=0;
32. }
33.
34. //返回顶点数
35. int GetVexNum()
36. {
37. return vexnum;
38. }
39.
//返回顶点位置
int Locate_Vex(string v)
40. {
41. for(int i=0;i<vexnum;i++)
42. if(vertices[i].data == v)
43. return i;
44. return -1;
45. }
46.
//构造无向图
47. void Create_NDGraph()
48. {
49. //构造无向图
50. string v1,v2;
51. int i,j,k;
52. cout<<"输入顶点数和边数:";
53. cin>>vexnum>>arcnum;
54. while(vexnum>20)
55. {
56. cout<<"请输入少于20个顶点(重新输入顶点数和边数):";
57. cin>>vexnum>>arcnum;
58. }
59.
60. cout<<"输入顶点名称:";
61. for(i=0;i<vexnum;i++)
62. {
63. cin>>vertices[i].data;
64. vertices[i].firstarc=NULL;
65. }
66.
67. for(k=0;k<arcnum;k++)
68. {
69. cout<<"输入每条边对应的两个顶点:";
70. cin>>v1>>v2;
71.
72. i=Locate_Vex(v1);
73. j=Locate_Vex(v2);
74.
75. while(i == -1 || j == -1)
76. {
77. cout<<"顶点中有不符合要求的,请重新输入:";
78. cin>>v1>>v2;
79. i=Locate_Vex(v1);
80. j=Locate_Vex(v2);
81. }
82.
83. ArcNode *p=new ArcNode;
84. p->adjvex=j;
85. p->nextarc=vertices[i].firstarc;
86. vertices[i].firstarc=p;
87.
88. //置对称边
89. ArcNode *q=new ArcNode;
90. q->adjvex=i;
91. q->nextarc=vertices[j].firstarc;
92. vertices[j].firstarc=q;
93. }
94. cout<<"无向图构造完成"<<endl;
95. }
96. void DFS_Traverse()
97. {
98. for(int i=0;i<vexnum;i++)
99. visited[i]=false;
100. for(i=0;i<vexnum;i++)
101. if(!visited[i])
102. DFS(i);
103. }
104.
//深度优先遍历
105. void DFS(int v)
106. {
107. visited[v]=true;
108. cout<<vertices[v].data<<" ";
109. ArcNode *p;
110. int w;
111. for(p=vertices[v].firstarc;p;p=p->nextarc)
112. {
113. w=p->adjvex;
114. if(!visited[w])
115. DFS(w);
116. }
117. }
118.
//广度优先遍历
119. void BFS_Traverse()
120. {
121. for(int i=0;i<vexnum;i++)
122. visited[i]=false;
123. for(i=0;i<vexnum;i++)
124. if(!visited[i])
125. BFS(i);
126. }
127.
128.//广度
129. void BFS(int v)
130. {
131. visited[v]=true;
132. cout<<vertices[v].data<<" ";
133. queue<int> qu;
134. int w,k;
135. ArcNode *p=NULL;
136. qu.push(v);
137. while(!qu.empty())
138. {
139. w=qu.front();
140. qu.pop();
141. for(p=vertices[w].firstarc;p;p=p->nextarc)
142. {
143. k=p->adjvex;
144. if(!visited[k])
145. {
146. visited[k]=true;
147. cout<<vertices[k].data<<" ";
148. qu.push(k);
149. }
150. }
151. }
152. }
153.
//求出一条长度为l的从u到v的路径,d刚进来的时候是-1
154. void Print_X_Y_Path(int u,int v,int l,int d)
155. {
156.
157. int m;
158. d++;
159. visited[u]=true;
160. path[d]=u;
161. if(u == v && d == l) //找到一条路径
162. {
163. for(int i=0;i<l;i++)
164. cout<<vertices[ path[i] ].data<<"-->";
165. cout<<vertices[ path[i] ].data<<endl;
166. }
167. else if(u == v && d!=l)
168. {
169. //出现这种情况直接回溯上一顶点,不浪费时间去DFS
170. goto loop;
171. }
172. else
173. {
174. ArcNode *p=vertices[u].firstarc; //继续DFS
175. while(p)
176. {
177. m=p->adjvex;
178. if(!visited[m])
179. Print_X_Y_Path(m,v,l,d);
180. p=p->nextarc;
181. }
182. }
183. //恢复环境,使顶点可重新使用
184. //路径长度减一
185.loop: visited[u]=false;
186. d--;
187. }
188.
189. //找出从i到i的回路,思想和上面的类似
190. void Print_X_X_Path(int i,int j,int d)
191. {
192. int v,k;
193. ArcNode *p;
194. visited[i]=true;
195. d++;
196. path[d]=i;
197. if(i == j && d>2)
198. {
199. for(k=0;k<d;k++)
200. cout<<vertices[ path[k] ].data<<"-->";
201. cout<<vertices[ path[k] ].data<<endl;
202. }
203. else if(i == j && d==2) //一条边只可以走一次
204. goto lop;
205. else
206. {
207. p=vertices[i].firstarc;
208. while(p)
209. {
210. v=p->adjvex;
211. if(!visited[v] || v == j)
212. Print_X_X_Path(v,j,d);
213. p=p->nextarc;
214. }
215. }
216.
217.lop: visited[i]=false;
218. d--;
219. }
220.
221.};
主函数文件
- #include "graph.h"
2. #include <iostream>
3. #include <string>
4. using namespace std;
5.
6. int main()
7. {
8. NDGraph G;
9. string v1,v2;
10. int u,v;
11. int num;
12. G.Create_NDGraph();
13.
14. cout<<"图的深度优先遍历为:";
15. G.DFS_Traverse();
16. cout<<endl;
17.
18. cout<<"图的广度优先遍历为:";
19. G.BFS_Traverse();
20. cout<<endl;
21.
22. cout<<"输入两个顶点名称和一个数字,"<<endl;
23. cout<<"将输出长度为输入数字大小的两顶点间路径:";
24. cin>>v1>>v2>>num;
25.
26. u=G.Locate_Vex(v1);
27. v=G.Locate_Vex(v2);
28. if(u == -1 || v == -1)
29. {
30. cout<<"顶点中有不符合要求的,操作失败"<<endl;
31. }
32. else
33. {
34. for(int i=0;i<G.GetVexNum();i++)
35. visited[i]=false;
36. cout<<"顶点 "<<v1<<" 到 "<<v2<<" 长度为 "<<num<<" 的简单路径如下:"<<endl;
37. G.Print_X_Y_Path(u,v,num,-1);
38. }
39.
40. cout<<"输入一个顶点名称,将输出所有经过它的回路:";
41. cin>>v1;
42. u=G.Locate_Vex(v1);
43. if(u == -1)
44. {
45. cout<<"顶点不存在,操作失败"<<endl;
46. }
47. else
48. {
49. for(v=0;v<G.GetVexNum();v++)
50. visited[v]=false;
51. cout<<"经过顶点 "<<v1<<" 的所有回路如下:"<<endl;
52. G.Print_X_X_Path(u,u,-1);
53. }
54. return 0;
55. }
- 输入顶点数和边数:5 6
2. 输入顶点名称:v1 v2 v3 v4 v5
3. 输入每条边对应的两个顶点:v1 v2
4. 输入每条边对应的两个顶点:v1 v4
5. 输入每条边对应的两个顶点:v2 v4
6. 输入每条边对应的两个顶点:v2 v3
7. 输入每条边对应的两个顶点:v3 v5
8. 输入每条边对应的两个顶点:v4 v5
9. 无向图构造完成
10. 图的深度优先遍历为:v1 v4 v5 v3 v2
11. 图的广度优先遍历为:v1 v4 v2 v5 v3
12. 输入两个顶点名称和一个数字,
13. 将输出长度为输入数字大小的两顶点间路径:v1 v3 3
14. 顶点 v1 到 v3 长度为 3 的简单路径如下:
15. v1-->v4-->v5-->v3
16. v1-->v4-->v2-->v3
17. 输入一个顶点名称,将输出所有经过它的回路:v4
18. 经过顶点 v4 的所有回路如下:
19. v4-->v5-->v3-->v2-->v4
20. v4-->v5-->v3-->v2-->v1-->v4
21. v4-->v2-->v3-->v5-->v4
22. v4-->v2-->v1-->v4
23. v4-->v1-->v2-->v3-->v5-->v4
24. v4-->v1-->v2-->v4
25. Press any key to continue
下面是生成的无向图示例:
为了更好得理解回溯的过程,可以画画像下面这样的示意图,比如我求 V1 到 V3的长度为3的路径的过程
图可能和你画的不一样,但是主要就是理清一下思路,不会在一重重的递归中乱掉
5. #include <queue>
6. using namespace std;
7. bool visited[20];
8. int path[20];
9. struct ArcNode
10. {
11. int adjvex;
12. ArcNode *nextarc;
13. };
14.
15. struct VexNode
16. {
17. string data;
18. ArcNode *firstarc;
19. };
20.
21. class NDGraph
22. {
23. private:
24. VexNode vertices[20];
25. int vexnum;
26. int arcnum;
27. public:
28. NDGraph()
29. {
30. vexnum=0;
31. arcnum=0;
32. }
33.
34. //返回顶点数
35. int GetVexNum()
36. {
37. return vexnum;
38. }
39.
//返回顶点位置
int Locate_Vex(string v)
40. {
41. for(int i=0;i<vexnum;i++)
42. if(vertices[i].data == v)
43. return i;
44. return -1;
45. }
46.
//构造无向图
47. void Create_NDGraph()
48. {
49. //构造无向图
50. string v1,v2;
51. int i,j,k;
52. cout<<"输入顶点数和边数:";
53. cin>>vexnum>>arcnum;
54. while(vexnum>20)
55. {
56. cout<<"请输入少于20个顶点(重新输入顶点数和边数):";
57. cin>>vexnum>>arcnum;
58. }
59.
60. cout<<"输入顶点名称:";
61. for(i=0;i<vexnum;i++)
62. {
63. cin>>vertices[i].data;
64. vertices[i].firstarc=NULL;
65. }
66.
67. for(k=0;k<arcnum;k++)
68. {
69. cout<<"输入每条边对应的两个顶点:";
70. cin>>v1>>v2;
71.
72. i=Locate_Vex(v1);
73. j=Locate_Vex(v2);
74.
75. while(i == -1 || j == -1)
76. {
77. cout<<"顶点中有不符合要求的,请重新输入:";
78. cin>>v1>>v2;
79. i=Locate_Vex(v1);
80. j=Locate_Vex(v2);
81. }
82.
83. ArcNode *p=new ArcNode;
84. p->adjvex=j;
85. p->nextarc=vertices[i].firstarc;
86. vertices[i].firstarc=p;
87.
88. //置对称边
89. ArcNode *q=new ArcNode;
90. q->adjvex=i;
91. q->nextarc=vertices[j].firstarc;
92. vertices[j].firstarc=q;
93. }
94. cout<<"无向图构造完成"<<endl;
95. }
96. void DFS_Traverse()
97. {
98. for(int i=0;i<vexnum;i++)
99. visited[i]=false;
100. for(i=0;i<vexnum;i++)
101. if(!visited[i])
102. DFS(i);
103. }
104.
//深度优先遍历
105. void DFS(int v)
106. {
107. visited[v]=true;
108. cout<<vertices[v].data<<" ";
109. ArcNode *p;
110. int w;
111. for(p=vertices[v].firstarc;p;p=p->nextarc)
112. {
113. w=p->adjvex;
114. if(!visited[w])
115. DFS(w);
116. }
117. }
118.
//广度优先遍历
119. void BFS_Traverse()
120. {
121. for(int i=0;i<vexnum;i++)
122. visited[i]=false;
123. for(i=0;i<vexnum;i++)
124. if(!visited[i])
125. BFS(i);
126. }
127.
128.//广度
129. void BFS(int v)
130. {
131. visited[v]=true;
132. cout<<vertices[v].data<<" ";
133. queue<int> qu;
134. int w,k;
135. ArcNode *p=NULL;
136. qu.push(v);
137. while(!qu.empty())
138. {
139. w=qu.front();
140. qu.pop();
141. for(p=vertices[w].firstarc;p;p=p->nextarc)
142. {
143. k=p->adjvex;
144. if(!visited[k])
145. {
146. visited[k]=true;
147. cout<<vertices[k].data<<" ";
148. qu.push(k);
149. }
150. }
151. }
152. }
153.
//求出一条长度为l的从u到v的路径,d刚进来的时候是-1
154. void Print_X_Y_Path(int u,int v,int l,int d)
155. {
156.
157. int m;
158. d++;
159. visited[u]=true;
160. path[d]=u;
161. if(u == v && d == l) //找到一条路径
162. {
163. for(int i=0;i<l;i++)
164. cout<<vertices[ path[i] ].data<<"-->";
165. cout<<vertices[ path[i] ].data<<endl;
166. }
167. else if(u == v && d!=l)
168. {
169. //出现这种情况直接回溯上一顶点,不浪费时间去DFS
170. goto loop;
171. }
172. else
173. {
174. ArcNode *p=vertices[u].firstarc; //继续DFS
175. while(p)
176. {
177. m=p->adjvex;
178. if(!visited[m])
179. Print_X_Y_Path(m,v,l,d);
180. p=p->nextarc;
181. }
182. }
183. //恢复环境,使顶点可重新使用
184. //路径长度减一
185.loop: visited[u]=false;
186. d--;
187. }
188.
189. //找出从i到i的回路,思想和上面的类似
190. void Print_X_X_Path(int i,int j,int d)
191. {
192. int v,k;
193. ArcNode *p;
194. visited[i]=true;
195. d++;
196. path[d]=i;
197. if(i == j && d>2)
198. {
199. for(k=0;k<d;k++)
200. cout<<vertices[ path[k] ].data<<"-->";
201. cout<<vertices[ path[k] ].data<<endl;
202. }
203. else if(i == j && d==2) //一条边只可以走一次
204. goto lop;
205. else
206. {
207. p=vertices[i].firstarc;
208. while(p)
209. {
210. v=p->adjvex;
211. if(!visited[v] || v == j)
212. Print_X_X_Path(v,j,d);
213. p=p->nextarc;
214. }
215. }
216.
217.lop: visited[i]=false;
218. d--;
219. }
220.
221.};
主函数文件
- #include "graph.h"
2. #include <iostream>
3. #include <string>
4. using namespace std;
5.
6. int main()
7. {
8. NDGraph G;
9. string v1,v2;
10. int u,v;
11. int num;
12. G.Create_NDGraph();
13.
14. cout<<"图的深度优先遍历为:";
15. G.DFS_Traverse();
16. cout<<endl;
17.
18. cout<<"图的广度优先遍历为:";
19. G.BFS_Traverse();
20. cout<<endl;
21.
22. cout<<"输入两个顶点名称和一个数字,"<<endl;
23. cout<<"将输出长度为输入数字大小的两顶点间路径:";
24. cin>>v1>>v2>>num;
25.
26. u=G.Locate_Vex(v1);
27. v=G.Locate_Vex(v2);
28. if(u == -1 || v == -1)
29. {
30. cout<<"顶点中有不符合要求的,操作失败"<<endl;
31. }
32. else
33. {
34. for(int i=0;i<G.GetVexNum();i++)
35. visited[i]=false;
36. cout<<"顶点 "<<v1<<" 到 "<<v2<<" 长度为 "<<num<<" 的简单路径如下:"<<endl;
37. G.Print_X_Y_Path(u,v,num,-1);
38. }
39.
40. cout<<"输入一个顶点名称,将输出所有经过它的回路:";
41. cin>>v1;
42. u=G.Locate_Vex(v1);
43. if(u == -1)
44. {
45. cout<<"顶点不存在,操作失败"<<endl;
46. }
47. else
48. {
49. for(v=0;v<G.GetVexNum();v++)
50. visited[v]=false;
51. cout<<"经过顶点 "<<v1<<" 的所有回路如下:"<<endl;
52. G.Print_X_X_Path(u,u,-1);
53. }
54. return 0;
55. }
- 输入顶点数和边数:5 6
2. 输入顶点名称:v1 v2 v3 v4 v5
3. 输入每条边对应的两个顶点:v1 v2
4. 输入每条边对应的两个顶点:v1 v4
5. 输入每条边对应的两个顶点:v2 v4
6. 输入每条边对应的两个顶点:v2 v3
7. 输入每条边对应的两个顶点:v3 v5
8. 输入每条边对应的两个顶点:v4 v5
9. 无向图构造完成
10. 图的深度优先遍历为:v1 v4 v5 v3 v2
11. 图的广度优先遍历为:v1 v4 v2 v5 v3
12. 输入两个顶点名称和一个数字,
13. 将输出长度为输入数字大小的两顶点间路径:v1 v3 3
14. 顶点 v1 到 v3 长度为 3 的简单路径如下:
15. v1-->v4-->v5-->v3
16. v1-->v4-->v2-->v3
17. 输入一个顶点名称,将输出所有经过它的回路:v4
18. 经过顶点 v4 的所有回路如下:
19. v4-->v5-->v3-->v2-->v4
20. v4-->v5-->v3-->v2-->v1-->v4
21. v4-->v2-->v3-->v5-->v4
22. v4-->v2-->v1-->v4
23. v4-->v1-->v2-->v3-->v5-->v4
24. v4-->v1-->v2-->v4
25. Press any key to continue
下面是生成的无向图示例:
为了更好得理解回溯的过程,可以画画像下面这样的示意图,比如我求 V1 到 V3的长度为3的路径的过程
图可能和你画的不一样,但是主要就是理清一下思路,不会在一重重的递归中乱掉