最短路径问题
题目大意:
有A、B、C、D、E、F六个地方,A到B用时12,B到C用时10,C到D用时3,D到E用时4,E到F用时2,F到A用时16,B到F用时7,C到E用时5,C到F用时6,要求输入两个地方,求最短用时,以及路径。
测试用例举例
输入:C E(以空格分开)
输出:
5
C E
用Dijkstra 算法求解:
- 算法思路
Dijkstra算法输入加权有向图G和源点s,获得到其他所有顶点之间的最短路径距离。
此外,需要集合S,其包含N个布尔值,用来记录已求出最短路径的顶点;集合U,用来记录还未求出最短距离的顶点;集合distance,用来记录到各顶点距离;集合prenode,记录最短路径中各顶点的父节点。 - 流程
1、初始时,S只包含起点s,U包含除s外的所有顶点,初始距离distance和prenode,未知父节点用-1表示;
2、从U中选出“距离最短的顶点K”,并将K加入到S中,同时从U中删除K;
3、更新distance,更新prenode
4、重复(2)(3),直到遍历完所有顶点。
实现
代码核心参考https://blog.youkuaiyun.com/doufei_ccst/article/details/7841311
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
const int Max = 6;
int graph[][Max] = { //定义有向图
{0,12,INT_MAX,INT_MAX,INT_MAX,INT_MAX},
{INT_MAX,0,10,INT_MAX,INT_MAX,7},
{INT_MAX,INT_MAX,0,3,5,6},
{INT_MAX,INT_MAX,INT_MAX,0,4,INT_MAX},
{INT_MAX,INT_MAX,INT_MAX,INT_MAX,0,2},
{16,INT_MAX,INT_MAX,INT_MAX,INT_MAX,0}
};
int scaner(char input) //键盘输入ABCDEF转为数字012345
{
int num;
switch(input)
{
case 'A':
num = 0;
break;
case 'B':
num = 1;
break;
case 'C':
num = 2;
break;
case 'D':
num = 3;
break;
case 'E':
num = 4;
break;
case 'F':
num = 5;
break;
default :
cout <<"your input is error"<<endl;
}
return num;
}
char numtochar(int input) // 矩阵索引012345转为ABCDE
{
char num;
switch(input)
{
case 0:
num = 'A';
break;
case 1:
num = 'B';
break;
case 2:
num = 'C';
break;
case 3:
num = 'D';
break;
case 4:
num = 'E';
break;
case 5:
num = 'F';
break;
default :
cout <<"your input is error! please input again, Note: case sensitive,just(ABCDEF)"<<endl;
}
return num;
}
void Dijkstra(const int numnode, const int startnode,int graph[][Max], int *distance,int *prenode)
/*节点数, 源节点, 有向图邻接矩阵, 源节点到达各个节点的距离, 各个节点的前一个节点*/
{
vector<bool> isInS; //是否已经在S集合中
isInS.reserve(0);
isInS.assign(numnode, false); //初始化,所有的节点都不在S集合中
/*初始化distance和prenode数组*/
for(int i =0; i < numnode; ++i)
{
distance[ i ] = graph[ startnode ][ i ];
if(graph[ startnode ][ i ] < INT_MAX)
prenode[ i ] = startnode;
else
prenode[ i ] = -1; //表示还不知道前一个节点是什么
}
prenode[ startnode ] = -1;
isInS[startnode] = true; //开始节点放入S集合中
int u = startnode;
for (int i = 1; i < numnode; i ++) //这里循环从1开始是因为开始节点已经存放在S中了,还有numnode-1个节点要处理
{
/*选择distance最小的一个节点*/
int nextnode = u;
int tempDistance = INT_MAX;
for(int j = 0; j < numnode; ++j)
{
if((isInS[j] == false) && (distance[j] < tempDistance)) //寻找不在S集合中的distance最小的节点
{
nextnode = j;
tempDistance = distance[j];
}
}
isInS[nextnode] = true; //放入S集合中
u = nextnode; //下一次寻找的开始节点
/*更新distance*/
for (int j =0; j < numnode; j ++)
{
if (isInS[j] == false && graph[u][j] < INT_MAX)
{
int temp = distance[ u ] + graph[ u ][ j ];
if (temp < distance[ j ])
{
distance[ j ] = temp;
prenode[ j ] = u;
}
}
}
}
}
int main()
{
int distance[Max];
int prenode[Max];
char inchar[4];
cout <<"please input two char in {ABCDE}:";
L1: cin.get(inchar, 4).get();
int startnode = scaner(inchar[0]);
int endnode = scaner(inchar[2]);
if(startnode<0 || startnode>5 || endnode<0 || endnode>5 )
{
goto L1;
}
Dijkstra(Max,startnode,graph, distance, prenode);
cout << "the distance is: "<<distance[endnode]<<endl;
cout <<"the trace is: ";
int index = endnode;
stack<int> trace;
while(prenode[index] != -1)
{
trace.push(prenode[index]);
index = prenode[index];
}
while(!trace.empty())
{
cout <<numtochar(trace.top())<<" ";
trace.pop();
}
cout <<numtochar(endnode)<<endl;
return 0;
}
结果
参考
1. https://blog.youkuaiyun.com/doufei_ccst/article/details/7841311
2. https://blog.youkuaiyun.com/heroacool/article/details/51014824
`