最短路径两种算法

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值