题目描述
给出一个图的邻接矩阵,输入顶点v,用迪杰斯特拉算法求顶点v到其它顶点的最短路径。
输入
第一行输入t,表示有t个测试实例
第二行输入顶点数n和n个顶点信息
第三行起,每行输入邻接矩阵的一行,以此类推输入n行
第i个结点与其它结点如果相连则为距离,无连接则为0,数据之间用空格
隔开。第四行输入v0,表示求v0到其他顶点的最短路径距离
以此类推输入下一个示例
输出
对每组测试数据,输出:
每行输出v0到某个顶点的最短距离和最短路径
每行格式:v0编号-其他顶点编号-最短路径值----[最短路径]。没有路径输出:v0编号-其他顶点编号--1。具体请参考示范数据
输入样例1
2
5 0 1 2 3 4
0 5 0 7 15
0 0 5 0 0
0 0 0 0 1
0 0 2 0 0
0 0 0 0 0
0
6 V0 V1 V2 V3 V4 V5
0 0 10 0 30 100
0 0 5 0 0 0
0 0 0 50 0 0
0 0 0 0 0 10
0 0 0 20 0 60
0 0 0 0 0 0
V0
输出样例1
0-1-5----[0 1 ]
0-2-9----[0 3 2 ]
0-3-7----[0 3 ]
0-4-10----[0 3 2 4 ]
V0-V1--1
V0-V2-10----[V0 V2 ]
V0-V3-50----[V0 V4 V3 ]
V0-V4-30----[V0 V4 ]
V0-V5-60----[V0 V4 V3 V5 ]
NOTICE:
正题:(1)题目输入时是以0来表示无连接,但在我们的算法中,带权值的邻接矩阵是以无穷来表示,因此在输入时要注意;(2)迪杰斯特拉算法(Dijkstra)中需要的变量有:D数组、final数组、path数组、flag,各个变量的作用在代码中注释;此算法与Prim算法大体上相似,但在很多实现细节上略有区别;(3)初始化时要注意flag为起点下标,起点的final和path做出相应修改,D初始化为起点到各个顶点的权值(区别于Prim是全部初始化为无穷),如果权值不为无穷,则修改相应的path,final除起点外全为0;初始化工作有点复杂感觉,很容易搞错,比如这里先把所有的final改为0后再单独把起点的final改为1;(4)循环主要分两个工作,一个是找flag,一个是更新D值;flag是D中最小且final为0的顶点的下标,找到后记得改final为1;更新D的条件要注意,是相加后小于,更新后记得修改path;(5)输出部分根据题目要求来即可,注意怎么判断一个顶点无最短路径:其D值为无穷
错误思路:一开始真的觉得这个算法跟Prim太像了,所以一开始初始化时跟Prim的做法一样,后来发现这样的话更新D时会出错,做法不可取,还是得根据ppt上例子的表格来推进这个算法
#include <iostream>
#include <stack>
using namespace std;
#define MAX 65535
class Graph
{
private:
string* data;
int** Matrix;
int vertexnum;
string v;//最短路径的起点
int find(string s)
{
for (int i = 0; i < vertexnum; i++)
if (s == data[i])
return i;
}
public:
Graph()
{
cin >> vertexnum;
data = new string[vertexnum];
for (int i = 0; i < vertexnum; i++)
cin >> data[i];
Matrix = new int* [vertexnum];
for (int i = 0; i < vertexnum; i++)
Matrix[i] = new int[vertexnum];
for (int i = 0; i < vertexnum; i++)
for (int j = 0; j < vertexnum; j++)
{
cin >> Matrix[i][j];
if (Matrix[i][j] == 0)//输入为0,表示两点之间无连接,修改为无穷
Matrix[i][j] = MAX;
}
cin >> v;
}
~Graph()
{
delete[]data;
for (int i = 0; i < vertexnum; i++)
delete[]Matrix[i];
delete[]Matrix;
}
void Dijkstra()
{
int* D = new int[vertexnum];//从顶点出发到某个顶点的当前最短路径长度(更新)
int* final = new int[vertexnum];//某个顶点是否已经加入到U集合中
int* path = new int[vertexnum];//每个顶点的最短路径上,到达该顶点的上一个顶点的下标
int flag;//D值最小且final为0的顶点的下标
//初始化
flag = find(v);
path[flag] = -1;
for (int i = 0; i < vertexnum; i++)
{
D[i] = Matrix[flag][i];
if (D[i] != MAX)
path[i] = flag;
final[i] = 0;
}
final[flag] = 1;
//循环
for (int i = 0; i < vertexnum - 1; i++)
{
//找flag
int tmp = MAX;
for (int j = 0; j < vertexnum; j++)
if (final[j] == 0 && D[j] < tmp)
{
tmp = D[j];
flag = j;
}
final[flag] = 1;
//更新D
for (int j = 0; j < vertexnum; j++)
if (D[flag] + Matrix[flag][j] < D[j])
{
D[j] = D[flag] + Matrix[flag][j];
path[j] = flag;
}
}
//输出
for (int i = 0; i < vertexnum; i++)
{
//特殊情况,无最短路径
if (i != find(v) && D[i] == MAX)
{
cout << data[find(v)] << "-" << data[i] << "--1" << endl;
continue;
}
if (i != find(v))
{
cout << data[find(v)] << "-" << data[i] << "-" << D[i] << "----[";
//输出路径
int k = i;
stack<int> s;
while (k != -1)
{
s.push(k);
k = path[k];
}
while (!s.empty())
{
cout << data[s.top()] << " ";
s.pop();
}
cout << "]" << endl;
}
}
}
};
int main()
{
int t;
cin >> t;
while (t--)
{
Graph g;
g.Dijkstra();
}
return 0;
}