介绍两种求最短路径的算法
迪杰斯特拉算法
题目介绍
输入形式
输入的第一行包含2个正整数n和s,表示图中共有n个顶点,且源点为s。其中n不超过50,s小于n。以后的n行中每行有n个用空格隔开的整数。对于第i行的第j个整数,如果大于0,则表示第i个顶点有指向第j个顶点的有向边,且权值为对应的整数值;如果这个整数为0,则表示没有i指向j的有向边。当i和j相等的时候,保证对应的整数为0。
输出形式
只有一行,共有n-1个整数,表示源点至其它每一个顶点的最短路径长度。如果不存在从源点至相应顶点的路径,输出-1。请注意行尾输出换行。
样例输入
4 1
0 3 0 1
0 0 4 0
2 0 0 0
0 0 1 0
样例输出
6 4 7
算法介绍
dist数组:源点到其他顶点的距离
flag数组:源点到其他顶点的最短距离是否求出,求出为1,否则为0
迪杰斯特拉算法就是不断更新dist数组(每一次都从新出现的到源点最短的顶点出发),最后dist数组里的就是源点到其他点的最短距离
0 | 1 | 2 | 3 | |
dist0 | inf | 0 | 4 | inf |
dist1 | 6(2+4<inf) | 0 | 4 | inf(inf+4>inf) |
dist2 | 6 | 0 | 4 | 7(6+1<inf) |
代码实现
#include <iostream>
#define inf 88888888
#define maxsize 100
using namespace std;
int pre[maxsize]={0};
int dist[maxsize]={0};
int root;
struct AdjMatrix
{
int vertex[maxsize];
int arcx[maxsize][maxsize];
int vexnum,arcnum;
};
void DJ(AdjMatrix *a)
{
int i,j,k,minlike,temp,flag[maxsize]={0};
for(i=0;i<a->vexnum;i++)
dist[i]=a->arcx[root][i];
flag[root]=1;
dist[root]=0;
for(i=1;i<a->vexnum;i++)
{
minlike=inf;
for(j=0;j<a->vexnum;j++)
{
if(flag[j]==0&&dist[j]<minlike)
minlike=dist[j],k=j;
}
flag[k]=1;
for(j=0;j<a->vexnum;j++)
{
temp=a->arcx[k][j]+minlike;
if(flag[j]==0&&temp<dist[j])
{
dist[j]=temp;
pre[j]=k;
}
}
}
for(i=0;i<a->vexnum;i++)\
if(i!=root)
{
if(dist[i]==inf)
cout<<-1<<" ";
else
cout<<dist[i]<<" ";
}
}
int main()
{
AdjMatrix a;
int x;
cin>>a.vexnum>>root;
for(int i=0;i<a.vexnum;i++)
for(int j=0;j<a.vexnum;j++)
{
cin>>x;
if(x)
a.arcx[i][j]=x;
else
a.arcx[i][j]=inf;
}
DJ(&a);
return 0;
}
弗洛伊德算法
题目介绍
输入形式
顶点个数n,以及n*n的邻接矩阵,其中不可达使用9999代替
输出形式
每两个顶点之间的最短路径和经过的顶点。注意:顶点自身到自身的dist值为0,path则为该顶点的编号
样例输入
4
9999 4 11 9999
6 9999 2 9999
1 9999 9999 1
9999 3 9999 9999
样例输出
from 0 to 0: dist = 0 path:0
from 0 to 1: dist = 4 path:0 1
from 0 to 2: dist = 6 path:0 1 2
from 0 to 3: dist = 7 path:0 1 2 3
from 1 to 0: dist = 3 path:1 2 0
from 1 to 1: dist = 0 path:1
from 1 to 2: dist = 2 path:1 2
from 1 to 3: dist = 3 path:1 2 3
from 2 to 0: dist = 1 path:2 0
from 2 to 1: dist = 4 path:2 3 1
from 2 to 2: dist = 0 path:2
from 2 to 3: dist = 1 path:2 3
from 3 to 0: dist = 6 path:3 1 2 0
from 3 to 1: dist = 3 path:3 1
from 3 to 2: dist = 5 path:3 1 2
from 3 to 3: dist = 0 path:3
算法介绍
迪杰斯特拉算法是优先选点,而弗洛伊德算法是优先选边,如果两点间存在中间节点可以缩短路径,就记录下中间节点,同时更新两点之间的最短路径长度,用三重循环遍历,处理完后的arcx数组里就是最短路径长度,路径则储存在一个个中间节点中。
P[i][j]:记录从i顶点到j顶点的中间节点k
arcx[i][j]:记录i顶点到j顶点的最短路径长度
0 | 1 | 2 | 3 | |
0 | 0 || inf | 0 || 4 | 1 || 6(4+2<11) | 2 || 7(4+2+1<11+1) |
1 | 2 || 3(2+1<6) | 0 || inf | 0 || 2 | 2 || 3(2+1<inf) |
2 | 0 || 1 | 3 || 4(1+3<1+4) | 0 || inf | 0 || 1 |
3 | 1 || 6(3+3(2+1)) | 0 || 3 | 1 || 5(3+2<inf) | 0 || inf |
代码实现
#include <iostream>
#define inf 9999
#define maxsize 100
using namespace std;
int P[maxsize][maxsize]={0};
struct AdjMatrix
{
int vertex[maxsize];
int arcx[maxsize][maxsize];
int vexnum,arcnum;
};
void printPath(int i,int j)//递归把中间节点全打印出来
{
int k=P[i][j];
if (k==0)
return;
printPath(i,k);
cout<<k<<" ";
printPath(k,j);
}
void printMatrix(AdjMatrix *a) {
int i,j;
for(i=0;i<a->vexnum;i++)
{
for (j=0;j<a->vexnum;j++)
{
if (j==i)
{
cout<<"from "<<i<<" to "<<j<<": dist = "<<0<<" path:"<<i<<endl;
continue;
}
cout<<"from "<<i<<" to "<<j<<": dist = "<<a->arcx[i][j]<<" path:"<<i<<" ";
printPath(i,j);
cout<<j<<endl;
}
}
}
void FD(AdjMatrix *a)
{
int i,j,k;
for(k=0;k<a->vexnum;k++)
for(i=0;i<a->vexnum;i++)
for(j=0;j<a->vexnum;j++)
if (a->arcx[i][k]+a->arcx[k][j]<a->arcx[i][j])
{
a->arcx[i][j]=a->arcx[i][k]+a->arcx[k][j];
P[i][j]=k;
}
printMatrix(a);
}
int main()
{
AdjMatrix a;
int root;
cin>>a.vexnum;
for(int i=0;i<a.vexnum;i++)
for(int j=0;j<a.vexnum;j++)
cin>>a.arcx[i][j];
FD(&a);
return 0;
}