path路径求解
关于使用迪杰特斯拉算法对路径求解
在使用迪杰特斯拉算法后我们会直接得到一个源点到另一个顶点的距离,以及根据path矩阵能得出所到各个顶点的前驱,接下来是小编写的一种算法,利用栈的思想将根据path矩阵得出源点到各个顶点的一个路径。
代码如下:
void Show_MG_path(MGraph* G, bool p[][MAX_VERTEX_NUM], Stack* s, VertexType v, VertexType v0) //打印某条路径
{
if (p[v][0] == false)
{
printf("can't get to V%d!!!\n", v);
return;
}
pushStack(s, v);
int a = -1;
a = get_progenitor(G, p, v);
while (a != v0)
{
pushStack(s, a);
a = get_progenitor(G, p, a);
}
pushStack(s, v0);
printf("The path to V%d: ", v);
while (!isEmptyStack(s))
{
printf("%5d", topStack(s));
popStack(s);
}
printf("\n");
}
VertexType get_progenitor(MGraph* G, bool p[][MAX_VERTEX_NUM], VertexType v) //得到某一节点的前驱
{
int i, j;
for ( i = 0; i < G->vexnum; i++)
{
if (i != v)
{
for ( j = 0; j < G->vexnum; j++)
{
if (j == v)
continue;
if (p[i][j] != p[v][j])
break;
}
}
if (j == G->vexnum)
return i;
}
return -1;
}
算法的思想为:
我们首先找到从源点到一个顶点的前驱顶点,然后将它压入栈底,在找到该前驱顶点的前驱顶点也压入栈底,利用循环来实现知道我们找到了有一个前驱顶点的前驱是源点,这个时候循环体也就结束了,然后我们再将栈依次弹出,就可以得到一个完整的路径
首先介绍返回某个顶点的前驱顶点VertexType()
形参列表为一个图,一个bool类型的path矩阵以及所要到达的顶点
我们首先借助两层for循环来找到和这个顶点状态一样的另一个顶点
我们应首先排除这个顶点自己,因为自己和自己的path那一行必定相同,所以第一个if就是排除自己;然后第二个if是跳过自己那一列
因为要循环比较自己的所在那一行每一列的元素是否和别的行的一致,若初自己那一列与某一行的元素均相同,则这个元素必为他的前驱顶点,返回;知道循环体结束仍未找到则返回-1,不表示未找到。(这理解释可能有些含糊,不好意思)
就如上边这幅图,比如p[5]我们要找到他的前驱,我们可以看到他的前驱有0/3/4,所以我们要找到哪一行有0/3/4,我们发现p[3]里面正好含有,所以将3返回他的前驱顶点也就是V3,,,以此类推。
第一个算法有了第二个的基础就简单了
Show_MG_path()
首先判断所要到达的顶点的path矩阵首元素是否为TRUE,若不是说明这条路径根本没有或无穷;然后就是首先将这个元素本身压入栈底,利用get_progenitor()依次得到每个前驱,一次压入栈,最后一次弹出,即可得出一条路径。
希望对读者们有所帮助
接下来是源码以及运行结果:
"head.h"
#include<stdio.h>
#include<stdlib.h>
#define INFINITY 32767 //最大值
#define MAX_VERTEX_NUM 20 //最大顶点数
#define VertexType int //顶点向量的类型
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; //顶点向量
int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int vexnum; //图的顶点数
int arcnum; //图的弧数
}MGraph;
typedef struct node{ //用于存放路径的栈
int data[MAX_VERTEX_NUM];
int top;
int base;
}Stack;
bool g_final[MAX_VERTEX_NUM];
int init_MG_Arcs(MGraph* G);
void show_MG_Arcs(MGraph* G);
void shortesrPath_DIJ(MGraph* G, VertexType v0, bool p[][MAX_VERTEX_NUM], int* d);
void show_path(MGraph* G, bool p[][MAX_VERTEX_NUM]);
Stack* init_Stack();
int isEmptyStack(Stack* s);
int isFullStack(Stack* s);
void pushStack(Stack* s, int oper);
void popStack(Stack* s);
int topStack(Stack* s);
void Show_MG_path(MGraph* G, bool p[][MAX_VERTEX_NUM], Stack* s, VertexType v, VertexType v0);
VertexType get_progenitor(MGraph* G, bool p[][MAX_VERTEX_NUM], VertexType v);
“main.cpp”
#include"head.h"
int main()
{
MGraph g;
init_MG_Arcs(&g); //初始化邻接矩阵
show_MG_Arcs(&g); //打印邻接矩阵
bool path[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //存放最短路径
int length[MAX_VERTEX_NUM]; //存放最短路径长度
int v0;
printf("请输入源点: ");
scanf("%d", &v0);
shortesrPath_DIJ(&g, v0, path, length);
show_path(&g, path);
Stack* s[MAX_VERTEX_NUM];
for (int i = 0; i < g.vexnum; i++)
s[i] = init_Stack();
printf("请输入终点: ");
int v;
scanf("%d", &v);
Show_MG_path(&g, path, *(s+v), v, v0);
return 0;
}
int init_MG_Arcs(MGraph* G) //初始化邻接矩阵
{
int v0, v, weight;
printf("请输入图顶点的个数以及弧数: ");
scanf("%d%d", &G->vexnum, &G->arcnum);
for (int i = 0; i < G->vexnum; i++)
for (int j = 0; j < G->vexnum; j++)
G->arcs[i][j] = INFINITY;
printf("请输入从某一顶点到另一顶点的顶点序号以及权重: \n");
printf("(例如: V0->V2, 权重: 20), Input: 0 2 20\n");
for (int i = 0; i < G->arcnum; i++)
{
printf("第%d条弧: ", i + 1);
scanf("%d%d%d", &v0, &v, &weight);
G->arcs[v0][v] = weight;
}
return 1;
}
void show_MG_Arcs(MGraph* G) //打印邻接矩阵
{
printf("改图的邻接矩阵为: \n");
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
printf("%13d", G->arcs[i][j]);
printf("\n");
}
}
void shortesrPath_DIJ(MGraph* G, VertexType v0, bool p[][MAX_VERTEX_NUM], int* d) //迪杰斯特拉算法
{
int v, w, min;
for (v = 0; v < G->vexnum; v++)
{
g_final[v] = false;
*(d + v) = G->arcs[v0][v];
for (w = 0; w < G->vexnum; w++)
p[v][w] = false;
if (*(d + v) < INFINITY)
{
p[v][v0] = true;
p[v][v] = true;
}
}
*(d + v0) = 0; //求解自己到自己的路径,默认找到
g_final[v0] = true; //初始化
p[v0][0] = true;
for (int i = 1; i < G->vexnum; i++) //主循环
{
min = INFINITY;
for (w = 0; w < G->vexnum; w++)
{
if (!g_final[w])
{
if (*(d + w) < min)
{
v = w;
min = *(d + w);
}
}
}
if (min != INFINITY) //判断真正意义上的找到最小值
{
g_final[v] = true; //找到 v0->v 的最短路径
}
if (v != G->vexnum)
{
for (w = 0; w < G->vexnum; w++)
{
if (!g_final[w] && (min + G->arcs[v][w] < *(d + w)))
{
*(d + w) = min + G->arcs[v][w];
/*p[w] = p[v];*/ //这种写法不可以
for (int i = 0; i < G->vexnum; i++)
p[w][i] = p[v][i];
p[w][w] = true;
}
}
}
}
}
void show_path(MGraph* G,bool p[][MAX_VERTEX_NUM])
{
for (int i = 0; i < G->vexnum; i++)
{
for (int j = 0; j < G->vexnum; j++)
printf("%5d", p[i][j]);
printf("\n");
}
}
Stack* init_Stack() //初始化一个顺序栈
{
Stack* s = (Stack*)malloc(sizeof(Stack));
s->top = -1;
s->base = -1;
return s;
}
int isEmptyStack(Stack* s) //判断栈是否为空栈
{
if (s->top == s->base)
return 1;
else
return 0;
}
int isFullStack(Stack* s) //判断栈是否为栈满
{
if (s->top == MAX_VERTEX_NUM - 1)
return 1;
else
return 0;
}
void pushStack(Stack* s, int oper) //压栈操作
{
if (isFullStack(s))
{
printf("该栈已满,压栈操作失败!\n");
}
else
{
s->top++;
s->data[s->top] = oper;
}
}
void popStack(Stack* s) //弹栈操作
{
if (isEmptyStack(s))
{
printf("本栈已空,弹栈操作失败!\n");
}
else
{
s->top--;
}
}
int topStack(Stack* s) //输出栈顶元素
{
if (isEmptyStack(s))
{
printf("本栈已空,输出栈顶元素失败!\n");
return 0;
}
else
{
return s->data[s->top];
}
}
void Show_MG_path(MGraph* G, bool p[][MAX_VERTEX_NUM], Stack* s, VertexType v, VertexType v0) //打印某条路径
{
if (p[v][0] == false)
{
printf("can't get to V%d!!!\n", v);
return;
}
pushStack(s, v);
int a = -1;
a = get_progenitor(G, p, v);
while (a != v0)
{
pushStack(s, a);
a = get_progenitor(G, p, a);
}
pushStack(s, v0);
printf("The path to V%d: ", v);
while (!isEmptyStack(s))
{
printf("%5d", topStack(s));
popStack(s);
}
printf("\n");
}
VertexType get_progenitor(MGraph* G, bool p[][MAX_VERTEX_NUM], VertexType v) //得到某一节点的前驱
{
int i, j;
for ( i = 0; i < G->vexnum; i++)
{
if (i != v)
{
for ( j = 0; j < G->vexnum; j++)
{
if (j == v)
continue;
if (p[i][j] != p[v][j])
break;
}
}
if (j == G->vexnum)
return i;
}
return -1;
}
运行结果
希望对你们有所帮助 : )
@all侵权删