图结构练习——最短路径
Time Limit: 1000MS Memory limit: 65536K
题目描述
给定一个带权无向图,求节点1到节点n的最短路径。
输入
输入包含多组数据,格式如下。
第一行包括两个整数n m,代表节点个数和边的个数。(n<=100)
剩下m行每行3个正整数a b c,代表节点a和节点b之间有一条边,权值为c。
输出
每组输出占一行,仅输出从1到n的最短路径权值。(保证最短路径存在)
示例输入
3 2 1 2 1 1 3 1 1 0
示例输出
1 0
提示
来源
赵利强
示例程序
迪杰斯特拉算法
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <queue>
#define inf 999999
using namespace std;
int n, m;
int map[1010][1010], visit[1010], dis[1010];
//迪杰斯特拉算法:首先将所有的边都放到待选区中,也就是dis[], 从顶点开始,遍历这一行也就是两个节点之间最小边,找到这一行中的最小值,
// 并把弧头节点从待选区中去掉,也就是visit[]赋值为1, 然而此时的值并不一定最小,再把最小值和图中当前位置的权值相加
// 和待选区中比较,如果比待选区的小,就把它覆盖的待选区,
// 此算法类似于普里姆算法,同样是按照节点遍历顺序,寻求最小值,如果有更好的路径就更替
void ShortPathTable(int x)
{
int k, min;
visit[0] = 1; //从顶点n开始遍历,遍历就标记为已遍历
for(int i = 1; i < x; i++) //初始化辅助数组,使每一个辅助数组中存着当前行所有的数据
dis[i] = map[0][i];
for(int i = 1; i < x; i++) //对所有的顶点都遍历
{
min = inf; //初始化最小值,用来寻找这一行中最小的权值
for(int j = 0; j < x; j++) //遍历此行所有的数据,若数据没有遍历过并且小于最小值,赋值为最小值,并记录下当前的位置,
{
if(visit[j] == 0 && min > dis[j])
{
min = dis[j];
k = j; //记录下当前位置,用来寻找下一次要遍历的行
}
}
visit[k] = 1; //标记为已遍历,此列不在遍历
for(int j = 0; j < x; j++) //遍历k行所有的数据,把没有遍历过的数据和它之前的最小值与其他节点节点之间的权值之和相比较
{ //如果前一个最小值和其他节点的权值的和比待选区中的数值小,就替换,待选区中的值也是在不断的累加
if(visit[j] == 0 && dis[j] > map[k][j] + min)
{
dis[j] = map[k][j] + min;
}
}
}
cout << dis[x - 1] << endl;
}
int main()
{
while(cin >> n >> m)
{
memset(visit, 0, sizeof(visit)); //初始化
memset(map, 0, sizeof(map));
for(int i = 0; i < n ; i++) //初始化邻接矩阵,因为为无向图,以对角线对称,对角线处必定为0,其他位置赋值为无限大
{
for(int j = 0; j < n; j++)
{
if(i == j)
map[i][j] = 0;
else
map[i][j] = inf;
}
}
for(int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if(c < map[a - 1][b - 1]) //因为数组坐标从0开始,而输出的数据的坐标却是从1开始,将其变化为数组中坐标
map[a - 1][b - 1] = map[b - 1][a - 1] = c;
}
ShortPathTable(n);
}
return 0;
}
弗洛伊德算法
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <queue>
#define inf 999999
using namespace std;
int n, m;
int map[1010][1010], visit[1010], dis[1010];
//弗洛伊德算法,重复的执行迪杰斯特拉算法
void ShortPathTable()
{
for(int k = 0; k < n; k++) //k为中间节点,此算法的精髓在于,如果通过中间节点k到达比直接到达数值更小的话
{ //就把相加后的数值代替原来的权值,最后map[0][n-1]的权值就是第一个节点到第n个节点的最短路径
for(int i = 0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
if(map[i][j] > map[i][k] + map[k][j]) //如果直接到达的比通过中间变量更远的话,利用中间节点
{
map[i][j] = map[i][k] + map[k][j];
}
}
}
}
cout << map[0][n - 1] << endl;
}
int main()
{
while(cin >> n >> m)
{
memset(visit, 0, sizeof(visit)); //初始化
memset(map, 0, sizeof(map));
for(int i = 0; i < n ; i++) //初始化邻接矩阵,因为为无向图,以对角线对称,对角线处必定为0,其他位置赋值为无限大
{
for(int j = 0; j < n; j++)
{
if(i == j)
map[i][j] = 0;
else
map[i][j] = inf;
}
}
for(int i = 0; i < m; i++)
{
int a, b, c;
cin >> a >> b >> c;
if(c < map[a - 1][b - 1]) //因为数组坐标从0开始,而输出的数据的坐标却是从1开始,将其变化为数组中坐标
map[a - 1][b - 1] = map[b - 1][a - 1] = c;
}
ShortPathTable();
}
return 0;
}