Dijkstra 算法 与 prim算法 求解最小生成树 有点类似 ,不同的是:prime 算法 输出的是 所有点全部连通的最小路径长度 , 而 Dijikstra 求解 单源最小路径 则是求解 一个点 (单源 就是 这个意思) 到其他点的 最小路径长度, 下面 我会招贴的有 prim 算法的 代码 和 Dijkstra 算法的代码, 其中 在 更新 low【】数组 (prim) 与 dist【】数组 (Dijkstra)的值得时候 if 语句里面的比较条件 不相同 , 前者是:当mapp[pos][i] < low[i] 时 low[i] = mapp[pos][i], 更新最小值;后者是 当 dist[pos] + mapp[pos][i] < dist[i] (dist【】数组 存储 下标到 单源点 的最小距离 )时 dist[i] = dist[pos] + mapp[pos][i] , 同时 保存路径的 数组 path【】也要更新 为 path[i] = pos ;
下面 是 一组测试 数据
5 7
1 2 100
1 3 30
1 5 10
3 2 60
3 4 60
4 2 10
5 4 50
1
输出如下:
1 5 4 2 70
1 3 30
1 5 4 60
1 5 10
Dijkstra 代码 如下 :
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <stack>
using namespace std;
int mapp[110][110], dist[110], path[110];// mapp数组 存储 邻接矩阵 ;dist数组存储 下标到 单源点 的最小路径;path数组 存储 最小路径中 下标点所对应的 前面路径的末尾点 ,下标表示 下一路径的开始点
int n, m, v0;// n 表示 点的个数, m 表示 边的个数
void Dijkstra(int v0)
{
int i, j;
bool *visited =(bool*)malloc(sizeof(bool)*n);// 标记数组 看 该点 是否 已经查找过
for(i = 1; i <= n; i++)// 三个数组的初始化
{
if(mapp[v0][i] > 0 && i != v0)
{
dist[i] = mapp[v0][i];
path[i] = v0;
}
else
{
dist[i] = INT_MAX;// not combine with spot v0,未连接 初始位距离很大
path[i] = -1;// represent not have former spot
}
visited[i] = false;
}
visited[v0] = true;// v0 点 标记 已经查找
for(i = 1; i < n; i++)//遍历 查找 最小 路径 更新 dist 与 path 数组的值
{
int minn = INT_MAX;
int pos;
for(j = 1; j <= n; j++)
if(visited[j] == false && minn > dist[j])
minn = dist[j], pos = j;
visited[pos] = true;
for(j = 1; j <= n; j++)
if(visited[j] == false && mapp[pos][j] > 0 && minn+mapp[pos][j] < dist[j])
dist[j] = minn + mapp[pos][j], path[j] = pos;//更新
}
}
void ShowPath(int v, int v0)// 此函数 输出 v 点 到 v0 点的 路径
{
stack<int> s;
while(v != v0)
{
s.push(v);
v = path[v];
}
s.push(v0);
while(!s.empty())
{
cout<<s.top()<<" ";
s.pop();
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(mapp, 0, sizeof(mapp));// 初始化 为 0
for(int i = 1; i <= m; i++)
{
int a, b, s;
cin>>a>>b>>s;
mapp[a][b] = s;
mapp[b][a] = s;
}
cin>>v0;// 单源点
Dijkstra(v0);
for(int j = 1; j <= n; j++)
{
if(j != v0)
{
ShowPath(j, v0);
cout<<dist[j]<<endl;// 输出 其他店到 单源点的 最小路径长,
}
}
return 0;
}
下面是 prim 算法 大家 可以 简单的 比较一下 不同之处;
至于具体代码如何实现,现在结合POJ1258例题解释。代码如下:
#include <stdio.h>
#include <string.h>
#define MaxInt 0x3f3f3f3f
#define N 110
int map[N][N],low[N],visited[N]; //创建map二维数组储存图表,low数组记录每2个点间最小权值,visited数组标记某点是否已访问
int n;
int prim()
{
int i,j,pos,min,result=0;
memset(visited,0,sizeof(visited));
visited[1]=1;pos=1; //从某点开始,分别标记和记录该点
for(i=1;i<=n;i++) //第一次给low数组赋值
if(i!=pos) low[i]=map[pos][i];
for(i=1;i<n;i++) //再运行n-1次
{
min=MaxInt;
for(j=1;j<=n;j++) //找出最小权值并记录位置
if(visited[j]==0&&min>low[j])
{
min=low[j];pos=j;
}
result+=min; //最小权值累加
visited[pos]=1;//标记该点
for(j=1;j<=n;j++) //更新权值
if(visited[j]==0&&low[j]>map[pos][j])
low[j]=map[pos][j];
}
return result;
}
int main()
{
int i,v,j,ans;
while(scanf("%d",&n)!=EOF)
{
memset(map,MaxInt,sizeof(map)); //所有权值初始化为最大
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
scanf("%d",&v);
map[i][j]=map[i][j]=v;
}
ans=prim();
printf("%d\n",ans);
}
return 0;
}