C++ 图论之最短路径

Floyd算法

应用:

附C++代码:

//
//  1447.cpp
//  最短路
//
//  Created by chenmeiqi on 2019/4/9.
//  Copyright © 2019年 chenmeiqi. All rights reserved.
//

#include <iostream>
using namespace std;
#define N 100
#define M 1001          // 题目中 C<=1000,所以 1001 代表无穷
int weight[N][N];
int main(int argc, const char * argv[]) {
    int n,m;
    int a,b;
    while(cin>>n>>m){
        if(n==0 && m==0){
            break;
        }
        for(int i = 0; i < N; i++)
        {
            for(int j = 0; j < N; j++)
            {
                weight[i][j]=M;             // 初始化
            }
            weight[i][i]=0;         //  自己到自己的路径长度设为0
        }
        
        
        while(m--){                 // 读入已有路径
            cin>>a>>b;
            cin>>weight[a-1][b-1];
            weight[b-1][a-1]=weight[a-1][b-1];
        }
        for(int k=0;k<n;k++){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if (weight[i][k]+weight[k][j]<weight[i][j]) {       // 经过 k 后获得了更短的路径,更新该值
                        weight[i][j]=weight[i][k]+weight[k][j];
                    }
                    
                }
            }
        }
        cout<<weight[0][n-1]<<endl;         // 第一个到最后一个结点的距离
    }
    return 0;
}

Dijkstra算法

改写:

//
//  1447.cpp
//  最短路径_Dijkstra
//
//  Created by chenmeiqi on 2019/4/9.
//  Copyright © 2019年 chenmeiqi. All rights reserved.
//

#include <iostream>
#include <vector>
using namespace std;
#define M 1001
struct E{
    int next;           // 直接相邻的结点
    int c;              // 该边的权值
};
vector<E> edge[101];        // 邻接链表
bool mark[101];     // 标记,当mask[j]为true时表示结点j的最短路径长度已经得到,该结点已经加入集合K
int Dis[101]; // 距离向量,当mask[i]为true时,表示已得到最短路径长度;否则,表示所有从结点1出发,经过已知的最短路径达到集合K中的某结点,再经过一条边到达结点i的路径中最短的距离
int main(int argc, const char * argv[]) {
    int n,m;
    while(cin>>n>>m){
        if(n==0&&m==0){
            break;
        }
        for(int i=1;i<=n;i++){
            edge[i].clear();            // 初始化邻接链表
        }
        while(m--){
            int a,b,c;
            cin>>a>>b>>c;
            E tmp;
            tmp.c=c;
            tmp.next=b;
            edge[a].push_back(tmp);
            tmp.next=a;
            edge[b].push_back(tmp);     //将邻接信息加入邻接链表,由于原图为无向图,故每条边信息都要添加到其两个顶点的单链表中
        }
        for(int i=1;i<=n;i++){
            Dis[i]=M;          // 所有距离为1001,即不可达
            mark[i]=false;      // 所有结点不属于集合K
        }
        Dis[1]=0;           // 得到最近的点为结点1,长度为0
        mark[1]=true;       // 将结点1加入集合K
        int newP=1;         // 集合K中新加入的点为结点1
        for(int i=1;i<n;i++){
            for(int j=0;j<edge[newP].size();j++){
                int t=edge[newP][j].next;
                int c=edge[newP][j].c;
                if(mark[t]==false){
                    if(Dis[newP]+c<Dis[t]){
                        Dis[t]=Dis[newP]+c;
                    }
                }
            }
            int min=M;
            for(int j=1;j<=n;j++){
                if(mark[j]==false && Dis[j]<min){
                    min=Dis[j];
                    newP=j;
                }
            }
            mark[newP]=true;
        }
        cout<<Dis[n]<<endl;
    }
    return 0;
}

对于vector模拟链表,见博主另一篇文章 https://blog.csdn.net/qq_36770641/article/details/88978758

应用:

附C++代码:

//
//  1008.cpp
//  最短路径问题
//
//  Created by chenmeiqi on 2019/4/9.
//  Copyright © 2019年 chenmeiqi. All rights reserved.
//

#include <iostream>
#include <vector>
using namespace std;
#define N 1001
struct E{
    int next;
    int distance;
    int cost;
};
vector<E> edge[N];      // 邻接链表
int Dis[N];
int cost[N];
bool mark[N];
int main(int argc, const char * argv[]) {
    int n,m;
    int a,b,d,p;
    int s,t;            // 起点,终点
    while(cin>>n>>m){
        if(n==0 && m==0){
            break;
        }
        for(int i=1;i<=n;i++){      // 初始化
            edge[i].clear();
            Dis[i]=-1;
            cost[i]=0;
            mark[i]=false;
        }
        while(m--){             // 录入z已知信息
            cin>>a>>b>>d>>p;
            E e;
            e.next=b;
            e.distance=d;
            e.cost=p;
            edge[a].push_back(e);
            e.next=a;
            edge[b].push_back(e);
        }
        cin>>s>>t;
        Dis[s]=0;
        cost[s]=0;
        mark[s]=true;
        int newP=s;
        for(int i = 1; i < n; i++)
        {
            for(int j = 0; j < edge[newP].size(); j++)
            {
                int t=edge[newP][j].next;
                int d=edge[newP][j].distance;
                int c=edge[newP][j].cost;
                if(mark[t]==false){
                    if(Dis[t]==-1 || Dis[newP]+d<Dis[t] ||(Dis[newP]+d==Dis[t] && cost[newP]+c < cost[t])){     // 当距离更近或距离相等但花费更少时更新信息
                            Dis[t]=Dis[newP]+d;
                            cost[t]=cost[newP]+c;
                    }
                }
            }
            int min=123123123;
            for(int k=1;k<=n;k++){                  // 找到下一个最近点
                if(mark[k]==false && Dis[k]!=-1){
                    if(Dis[k]<min){
                        min=Dis[k];
                        newP=k;
                    }
                }
            }
            mark[newP]=true;
        }
        cout<<Dis[t]<<" "<<cost[t]<<endl;
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值