问题简述:在一个无向图中,如何判别两点间是否存在一条长度为K的简单路径?
算法思想:
为描述方便,设起始顶点为 src,目的顶点为 dst。
1)当 k == 0 时,如果此时 src == dst,则存在。否则不存在。
2)当 k >= 1时,当前点为 src,依次遍历与 src 相邻的顶点 vi,将问题递归为求起始顶点为 vi, 目的节点为 dst,长度为 k-1 的简单路径是否存在。
在算法的实现中,需要注意的是避免死循环问题。
1)避免从 vi 到 vj 后,又从 vj 返回到 vi,造成循环。
2)再者,假设 src 到 dst 的路径经过 src 的相邻节点 vj,虽然 vj 到 dst 可能不存在 k-1 的简单路径,但是可能存在其他长度的路径,这就需要增加一个辅助数组,用以标识 以 vj 为起点,到dst 长度为 k-1 的路径有没有尝试过,如果尝试过了就跳过,这样当求长度 k 为其它值的时候可以再次以 vj 为起点。
代码如下
#include<iostream>
using std::cout;
using std::endl;
#include<stack>
using std::stack;
#include<vector>
using std::vector;
#include<cstdlib>
using std::atoi;
#include<cassert>
template<size_t N>
bool HasSimpleKPath(int src, int dst, int k, int (&gm)[N][N], stack<int>& trace, vector<vector<bool> >& aux)
{
assert(k >= 0);
if(k == 0){
return src == dst;
}
if(!aux[src][k]){ // src has not visited it's children by k length.
aux[src][k] = true;
for(size_t i = 0; i < N; ++i){
if(gm[src][i] > 0){
int old = gm[src][i];
gm[src][i] = 0;
gm[i][src] = 0;
bool has = HasSimpleKPath(i, dst, k - 1, gm, trace, aux);
gm[src][i] = old;
gm[i][src] = old;
if(has){
trace.push(src);
return true;
}
}
}
}
return false;
}
测试代码如下:
int main(int argc, char* argv[]){
const int sz = 7;
int gm[sz][sz] = {
{0, 0, 0, 1, 1, 0, 0},
{0, 0, 1, 0, 1, 0, 0},
{0, 1, 0, 1, 0, 0, 0},
{1, 0, 1, 0, 0, 1, 1},
{1, 1, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0},
{0, 0, 0, 1, 0, 0, 0}
};
if(argc != 4){
std::cerr << "usage: " << argv[0] << " src dst k" << endl;
return 1;
}
int src, dst, k;
stack<int> trace;
src = atoi(argv[1]);
dst = atoi(argv[2]);
k = atoi(argv[3]);
vector<vector<bool> > aux(sz, vector<bool>(k + 1, false));
if(HasSimpleKPath(src, dst, k, gm, trace, aux)){
while(!trace.empty()){
cout << 'v' << trace.top() << "-->";
trace.pop();
}
cout << 'v' << dst << endl;
}
else{
cout << "Not found!" << endl;
}
return 0;
}
测试程序中的邻接矩阵所表示的图如下图所示 :