1.Dijkstra算法
(1)可以求已确定的单源点到其它各个顶点的最短路径,O(n²)
(2)可以求任意两个顶点间的最短路径,O(n³)
(3)要求权值必须为正
(4)按路径长度递增的次序输出结果
注意:顶点名用string[]存储而非char[],否则输出会出现问题
#include <iostream>
#include <cstring>
using namespace std;
class MGraph{
public:
MGraph(string a[],int n,int e);
void Dijkstra(int v);
int Min(int r[],int n);
private:
string vertex[10];//存放顶点名
int edge[10][10];//存放边
int vertexNum,edgeNum;
};
MGraph::MGraph(string a[],int n,int e){
int i,j,k,w;
vertexNum=n;
edgeNum=e;
for(i=0;i<vertexNum;i++)
vertex[i]=a[i];
for(i=0;i<vertexNum;i++)
for(j=0;j<vertexNum;j++)
if(i==j)
edge[i][j]=0;
else
edge[i][j]=1000;//假设权值最大是1000
for(k=0;k<edgeNum;k++){
cin>>i>>j>>w;
edge[i][j]=w;//有向图的边置权值
}
}
//求v到其它各个顶点的最短路径
void MGraph::Dijkstra(int v){
int i,k,num,dist[100];
string path[10];//记录最短路径的名字
for(i=0;i<vertexNum;i++){//初始化
dist[i]=edge[v][i];//邻接矩阵第v行
if(dist[i]!=1000)//假设边上权值最大为1000
path[i]=vertex[v]+vertex[i];//+是字符串的连接
else
path[i]="";
}
for(num=1;num<vertexNum;num++){
//在dist数组中找最小值并返回下标
k=Min(dist,vertexNum);
cout<<path[k]<<":"<<dist[k]<<endl;
for(i=0;i<vertexNum;i++)
if(dist[i]>dist[k]+edge[k][i]){
dist[i]=dist[k]+edge[k][i];
path[i]=path[k]+vertex[i];
}
dist[k]=0;//把k加入集合后,赋0避免重复查找
}
}
int MGraph::Min(int r[],int n){
int index=0,min=1000;
for(int i=0;i<n;i++){
if(r[i]!=0&&r[i]<min){
min=r[i];index=i;
}
}
return index;
}
int main()
{
//(0 1 10)(0 4 100)(0 3 30)(1 2 50)(2 4 10)(3 2 20)(3 4 60)
string ch[5]={"A","B","C","D","E"};
MGraph mg(ch,5,7);
mg.Dijkstra(0);
return 0;
}
运行结果
0 1 10
0 4 100
0 3 30
1 2 50
2 4 10
3 2 20
3 4 60
AB:10
AD:30
ADC:50
ADCE:60
2.Floyd算法
(1)能求任意两个顶点间的最短路径,时间复杂度是O(n³),不能求单源点最短路径
(2)权值可正可负
#include <iostream>
#include <cstring>
using namespace std;
class MGraph{
public:
MGraph(string a[],int n,int e);
void Floyd();
private:
string vertex[10];
int edge[10][10];
int vertexNum,edgeNum;
};
MGraph::MGraph(string a[],int n,int e){
int i,j,k,w;
vertexNum=n;edgeNum=e;
for(i=0;i<vertexNum;i++)
vertex[i]=a[i];
for(i=0;i<vertexNum;i++)
for(j=0;j<vertexNum;j++)
if(i==j)
edge[i][j]=0;//主对角线为0
else
edge[i][j]=1000;//假设边上权值最大为1000,一定要赋值,不能为0
for(k=0;k<edgeNum;k++){
cout<<"请输入边的两个起点和终点以及边的权值:";
cin>>i>>j>>w;
edge[i][j]=w;
}
}
void MGraph::Floyd(){
int i,j,k,x,y,dist[10][10];
string path[10][10];
//初始化
for(i=0;i<vertexNum;i++)
for(j=0;j<vertexNum;j++){
dist[i][j]=edge[i][j];
if(dist[i][j]!=1000)//假设权最大为1000
path[i][j]=vertex[i]+vertex[j];
else
path[i][j]="";
}
for(k=0;k<vertexNum;k++){//一个k值进行n次迭代
for(i=0;i<vertexNum;i++)
for(j=0;j<vertexNum;j++){
if(dist[i][k]+dist[k][j]<dist[i][j]){//上一步的dist
dist[i][j]=dist[i][k]+dist[k][j];//形成新的dist
path[i][j]=path[i][k]+path[k][j];
}
}
}
for(x=0;x<vertexNum;x++){
for(y=0;y<vertexNum;y++)
cout<<path[x][y]<<":"<<dist[x][y]<<"\t";
cout<<endl;
}
}
int main()
{
//(0 1 4)(0 2 11)(1 0 6)(1 2 2)(2 0 3)
string s[3]={"A","B","C"};
MGraph mg(s,3,5);
mg.Floyd();
return 0;
}
运行结果
请输入边的两个起点和终点以及边的权值:0 1 4
请输入边的两个起点和终点以及边的权值:0 2 11
请输入边的两个起点和终点以及边的权值:1 0 6
请输入边的两个起点和终点以及边的权值:1 2 2
请输入边的两个起点和终点以及边的权值:2 0 3
AA:0 AB:4 ABBC:6
BCCA:5 BB:0 BC:2
CA:3 CAAB:7 CC:0