找出从指定结点出发且长度为m的所有简单路径
作者: 冯向阳
时间限制: 1s
章节: 课程设计
问题描述
在使用图的邻接表ADT的基础上,设计一个算法,按照深度优先搜索的思想找出从指定结点出发且长度为m的所有简单路径。并将此算法加入到邻接表ADT中,在邻接表ADT中提供一个公有的成员函数FindPath(start, m)。
提示:
(1)这个问题相当于从指定结点开始深度优先遍历,而且遍历的深度正好为m。为此,在遍历时需要记住遍历的深度,当深度达到m时,就不需要递归了。此时需要输出这条路径,因此在遍历的过程中还需要记住整条路径。
(2)由于深度优先遍历是用递归实现的,所以FindPath函数最好也设计两个。一个是共有的FindPath函数,供用户使用(外壳);另一个是私有的FindPath函数,实现递归的遍历。公有的FingPath函数调用私有的FindPath函数找出这些路径。
(3)在调用递归的FindPath函数前,外壳函数还需要做一些辅助工作:
1)要找的是长度为m的简单路径,因此路径上不能有相同的结点,于是定义了一个数组visited记录结点是否在路径上。
2)当路径长度等于m时要输出这条路径,于是定义了一个数组stack保存这条路径。每访问一个结点,都要把结点记录在stack中。
3)递归的FindPath函数有6个参数。第1个参数是遍历的起点的序号;第2个参数是要求的路径长度;第3个参数是符合要求的路径数目;第4个参数是当前路径中的结点数,当前路径的长度是结点数减1;第5个参数是visited数组,记录结点是否在路径上;第6个参数是一个用于记录路径上结点序号的数组,作用和栈类似。
4)调用FindPath函数时要指出从哪一个结点出发,而递归的FingPath函数的参数是起点的序号。递归的FindPath函数首先将起点放入这条路径,并标记这个结点已被访问,然后判断路径长度是否是m。如果长度已达到m,则输出这条路径,并将最后一个结点从路径上删除,返回上一层调用,检查是否还有其它的途径;否则逐个检查起点的后继结点。如果该后继结点没有被访问过,则对该结点调用递归的FindPath函数继续寻找。在所有的后继都检查后,表示这条路径处理完毕。将起始结点从这条路径上删除,返回上一层调用。
参考函数原型:
(1)//找出从指定结点出发且长度为m的所有简单路径(外壳部分)
template<class TypeOfVer, class TypeOfEdge>
void adjlist_graph<TypeOfVer, TypeOfEdge>::FindPath(int start, int m);
(2)//找出从指定结点出发且长度为m的所有简单路径(递归部分)
template<class TypeOfVer, class TypeOfEdge>
void adjlist_graph<TypeOfVer, TypeOfEdge>::FindPath(int start, int m, int &count, int top, int visited[], int stack[]);
输入说明
第一行:图的类型
第二行:结点数
第三行:结点集
第四行:边数
第五行:边集
第六行:起点start
第七行:路径长度m
输出说明
第一行:顶点集
第二行:邻接表
空行
如无符合要求的路径:输出 0
否则: 路径输出(一条路径占一行)
路径数目
#include <iostream>
#include <string>
#include <queue>
#include <vector>
using namespace std;
template<class TypeOfEdge>
struct edgeNode
{
size_t data;
TypeOfEdge weight;
edgeNode<TypeOfEdge>* next;
edgeNode(const size_t& d, const TypeOfEdge& w, edgeNode<TypeOfEdge>* ptr = nullptr)
{
data = d;
weight = w;
next = ptr;
}
};
template<class TypeOfVer, class TypeOfEdge>
struct verNode
{
TypeOfVer ver;
edgeNode<TypeOfEdge>* head;
verNode(edgeNode<TypeOfEdge>* h = nullptr)
{
head = h;
}
};
template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph
{
private:
int Vers; // Number of vertices
verNode<TypeOfVer, TypeOfEdge>* verList;
string GraphKind;
void BFS_Util(queue<int>& q, vector<bool>& visited)
{
if (q.empty())
return;
int u = q.front();
cout << verList[u].ver;
q.pop();
edgeNode<TypeOfEdge>* curr = verList[u].head;
while (curr != nullptr)
{
size_t v = curr->data;
if (!visited[v])
{
q.push(v);
visited[v] = true;
}
curr = curr->next;
}
if (!q.empty())
{
cout << "->";
BFS_Util(q, visited);
}
}
public:
int Get_InDegree(int u, string& kd)
{
if (u < 0 || u >= Vers || kd == "UDG" || kd == "UDN")
return -1;
int inDegree = 0;
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
if (curr->data == u)
++inDegree;
curr = curr->next;
}
}
return inDegree;
}
void FindPath(int start, int m, int& count);
void FindPath(int start, int m, int& count, int top, int visited[], int stack[]);
void BFS_Traverse(int u)
{
vector<bool> visited(Vers, false);
queue<int> q;
q.push(u);
visited[u] = true;
BFS_Util(q, visited);
}
adjlist_graph(const string& kd, int vSize, const TypeOfVer d[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
}
}
adjlist_graph(const string& kd, int vSize, int eSize, const TypeOfVer d[], int** e) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int i = 0; i < eSize; ++i)
{
int u = e[i][0];
int v = e[i][1];
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, 0, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, 0, verList[v].head);
verList[v].head = newNode;
}
}
adjlist_graph(const string& kd, int vSize, int eSize, const TypeOfVer d[], int** e, const TypeOfEdge w[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int k = 0; k < eSize; ++k)
{
int u = e[k][0];
int v = e[k][1];
TypeOfEdge weight = w[k];
if (GraphKind == "DG" || GraphKind == "DN")
{
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
}
else
{
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, weight, verList[v].head);
verList[v].head = newNode;
}
}
}
~adjlist_graph()
{
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
edgeNode<TypeOfEdge>* temp = curr;
curr = curr->next;
delete temp;
}
}
delete[] verList;
}
void printAdjList()
{
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
cout << "->" << curr->data;
curr = curr->next;
}
cout << endl;
}
}
bool PrintMatrix()
{
cout << GraphKind << endl;
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
if (i != Vers - 1)
cout << " ";
}
cout << endl;
return true;
}
bool GetWeight(int u, int v, TypeOfEdge& w);
};
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::GetWeight(int u, int v, TypeOfEdge& w)
{
if (u < 0 || u >= Vers || v < 0 || v >= Vers)
return false;
edgeNode<TypeOfEdge>* curr = verList[u].head;
while (curr != nullptr)
{
if (curr->data == v)
{
w = curr->weight;
return true;
}
curr = curr->next;
}
return false;
}
template<class TypeOfVer, class TypeOfEdge>
void adjlist_graph<TypeOfVer, TypeOfEdge>::FindPath(int start, int mm, int& count)
{
int* visited = new int[Vers];
int* stack = new int[mm + 1];
for (int i = 0; i < Vers; ++i) visited[i] = 0;
FindPath(start, mm, count, 0, visited, stack);
delete[] visited;
delete[] stack;
}
template<class TypeOfVer, class TypeOfEdge>
void adjlist_graph<TypeOfVer, TypeOfEdge>::FindPath(int start, int mm, int& count, int top, int visited[], int stack[])
{
visited[start] = 1;
stack[top] = start;
if (top == mm)
{
for (int i = 0; i <= top; ++i)
{
cout << verList[stack[i]].ver;
if (i < top)
cout << "->";
}
cout << endl;
count++;
}
else
{
for (edgeNode<TypeOfEdge>* p = verList[start].head; p != nullptr; p = p->next)
{
if (!visited[p->data])
FindPath(p->data, mm, count, top + 1, visited, stack);
}
}
visited[start] = 0;
}
int main()
{
string graphType;
int n, m, count=0;
cin >> graphType >> n;
string* verArr = new string[n];
for (int i = 0; i < n; ++i)
{
cin >> verArr[i];
}
cin >> m;
int** edgeArr = new int* [m];
for (int i = 0; i < m; ++i)
{
edgeArr[i] = new int[2];
cin >> edgeArr[i][0] >> edgeArr[i][1];
}
int* weightArr = new int[m];
for (int i = 0; i < m; ++i)
{
weightArr[i] = 1;
}
int start, mm;
cin >> start >> mm;
adjlist_graph<string, int> graph(graphType, n, m, verArr, edgeArr, weightArr);
// 输出顶点集和邻接表
for (int i = 0; i < n; ++i)
{
cout << verArr[i];
if (i < n - 1) cout << " ";
}
cout << endl;
graph.printAdjList();
cout << endl;
graph.FindPath(start, mm, count);
cout << count;
// 释放动态内存
delete[] verArr;
for (int i = 0; i < m; ++i)
{
delete[] edgeArr[i];
}
delete[] edgeArr;
delete[] weightArr;
return 0;
}