一、题目描述
(1).求出有向图中从起点到终点的所有简单路径。其中起点和终点可以由用户自行设定。
(2).求出有向图中从起点到终点的指定长度(如K)的所有简单路径。其中起点和终点可以由用户自行设定。
二、解决方案
1.任务定义和问题分析
- 首先建立图的邻接矩阵来表示图,0表示无边,非0的n代表边的权值(边的长度);
- 用vector < int > path储存路径(path记录图的点来表示路径);
- 采用BFS(深度遍历)的方法来遍历所有的路径,符合的路径则进path并输出;
2.详细设计
a.建一个图的类,类里包含邻接矩阵的建立以及BFS算法的实现
#include<iostream>
#include<vector>
using namespace std;
class figure
{
private:
vector<int> path;//储存路径
int count;//图中点的个数
int** sz;//动态二维邻接矩阵数组的创立
int start;//起点
int end;//终点
int goal;//指定的路径长度
int temp;//path里的路径长度
public:
figure(int n, int start, int end, int k);//为邻接矩阵二维数组开空间,起点、终点、路径长度的确立
~figure();
void creat();//建立邻接矩阵
void dfs_findall(int v);//查找从起点到终点的所有路径(BFS遍历)
void dfs_findspecial(int v);//查找从起点到终点路径长度为goal的所有路径(BFS遍历)
void cout_path();//输出路径
int firstadj(int v, int cou);//查找下一个临接点
bool judge_circle(int &v, int &next);//判断此时的路径是简单路径(路径是否有环)
};
b.图的构造和析构函数:邻接矩阵二维数组开空间,起点、终点、路径长度的确立
figure::figure(int n, int sta, int en, int k)
{
start = sta;
end = en;
goal = k;
temp = 0;//现在路径的长度为0;
path.push_back(start);//现将起点放到路径里
count = n;
sz = new int* [n];
for (int i = 0; i < n; i++)
{
sz[i] = new int[n];
}
}
figure::~figure()
{
delete[]sz;
}
c.建立邻接矩阵:
void figure::creat()
{
int i, j, a;
for (i = 0; i < count; i++)
{
for (j = 0; j < count; j++)
{
cin >> a;
sz[i][j] = a;
}
}
}
d.查找从起点到终点的所有路径(BFS遍历)
void figure::dfs_findall(int v)//v代表现在遍历的点
{
if (v == end)//如果现在的点==终点输出路径并返回上一级
{
cout_path();
return;
}
int cou = 0;//v可能与多个点连接,cou表示:v相邻的第cou+1个点,此时cou=0表示与cou相邻的第1个点,
int next = firstadj(v, cou);//取得v相邻的第cou+1个点,
while (next != -1)//因为邻接矩阵的点为0,1,2,3,4......n没有负数的点,当点数为-1时代表v没有相邻的点了
{
while (judge_circle(v, next))//判断是否为简单路径,如果不是,再寻找下一个不和当前路径有环的相邻点
{
cou++;
next = firstadj(v, cou);
}
path.push_back(next);
dfs_findall(next);//开始BFS
path.pop_back();//回溯所做的工作,将path回溯到之前的状态
v = path.back();
cou++;//取v的下一个邻接点
next = firstadj(v, cou);
}
}
e.查找从起点到终点路径长度为goal的所有路径(BFS遍历),其思路与d.查找从起点到终点的所有路径(BFS遍历)类似,只是输出条件变了,多用了记录路径长度的temp,当现在的点v终点&&temp指定路径长度时,输出路径;
void figure::dfs_findspecial(int v)
{
if (v == end && temp == goal)//当现在的点v==终点&&temp==指定路径长度时,输出路径;
{
cout_path();
return;
}
if (v == end)//如果v==终点,但不是指定路径也返回
return;
int cou = 0;//v可能与多个点连接,cou表示:v相邻的第cou+1个点,此时cou=0表示与cou相邻的第1个点,
int next = firstadj(v, cou);//取得v相邻的第cou+1个点,
while (next != -1)//判断是否为简单路径,如果不是,再寻找下一个不和当前路径有环的相邻点
{
while(judge_circle(v, next))
{
cou++;
next = firstadj(v, cou);
}
vector<int>::iterator it = path.end()-1;
path.push_back(next);
temp += sz[*it][path.back()];//邻接矩阵数组的数据代表边的长度
dfs_findspecial(next);//开始BFS
temp -= sz[*it][path.back()];//回溯所做的工作,将path回溯到之前的状态
path.pop_back();
v = path.back();
cou++;
next = firstadj(v, cou);//取v的下一个邻接点
}
}
f.输出路径的函数
void figure::cout_path()
{
vector<int>::iterator it = path.begin();
for (; it < path.end() - 1; it++)
cout << *it << "->";
cout << *it << endl;
}
g.得到下一个邻接点的函数
int figure::firstadj(int v, int cou)
{
int i, a = -1, k = 0;//k是记录现在v的第k+1个点;
for (i = 0; i < count; i++)
{
if (sz[v][i] != 0)//如果此点存在
{
if (k == cou)//判断是否是要取v的第cou+1的点,如果是就返回
{
a = i;
break;
}
k++;
if (k > cou)
break;
}
}
return a;
}
h.判断v的邻接点如果进入路径是否仍然还是简单路径,将路径的所有点与邻接点比较,如果有重合的点(除了起点与终点)就不是简单路径
bool figure::judge_circle(int &v, int &next)
{
//将路径的所有点与邻接点比较,如果有重合的点(除了起点与终点)就不是简单路径
for (vector<int>::iterator it = path.begin()+1; it < path.end()-1; it++)
if (*it == next)
return true;
return false;
}
i.路径输出函数
void figure::cout_path()
{
vector<int>::iterator it = path.begin();
for (; it < path.end() - 1; it++)
cout << *it << "->";
cout << *it << endl;
}
三、输出样例
样例一:
样例二: