最短路径---Floyd-Warshall,Dijkstra,Bell-man

Floyd-Warshall的基本思想: 通过一个中转点不断地来松弛顶点的出边

//Floyd-Warshall算法核心语句
    for (int k = 1; k <= V; k++)
        for (int i = 1; i <= V; k++)
            for (int j = 1; j <= V; j++)
                if ( e[i][j] > e[i][k] + e[k][j] ) e[i][j] = e[i][k] + e[k][j]

/*
 *最短路径---Floyd-Warshall算法
 *2018/2/7
 */
#include <bits/stdc++.h>
using namespace std;

const int maxn = 101;
const int inf = 10001;

int e[maxn][maxn], V, E;

void pf() {
    for (int i = 1; i <= V; i++) {
        for (int j = 1; j <= V; j++) {
            cout << e[i][j] << " ";
        }
        cout << endl;
    }
}

int main() {

    int dis, t1, t2, t3;

    //录入顶点和边的个数
    cin >> V >> E;

    //初始化邻接矩阵
    for (int i = 1; i <= V; i++)
        for (int j = 1; j <= V; j++)
            if ( i == j ) e[i][j] = 0; //自己到自己的距离为0
            else e[i][j] = inf; //否则为无穷大

    //录入边
    for (int i = 1; i <= E; i++) {
        cin >> t1 >> t2 >> t3;
        e[t1][t2] = t3;
    }

    //利用Floyd-Warshall算法算出最短路径
    //       k为中转点
    for (int k = 1; k <= V; k++ ) {
        for (int i = 1; i <= V; i++) {
            for (int j = 1; j <= V; j++) {
                dis = e[i][k] + e[k][j]; //记录利用中转点后i到j的距离
                if ( dis < e[i][j] ) {
                    e[i][j] = dis;
                    pf();
                    system("pause");
                }
            }
        }
    }
    /**
    4 8
    1 2 2
    1 3 6
    1 4 4
    2 3 3
    3 1 7
    3 4 1
    4 1 5
    4 3 12
    **/
    return 0;
}

Dijkstra的基本思想:找到已知最短路径的顶点,利用该顶点不断地松弛顶点的出边

/*
 *最短路径---Dijkstra算法
 *2018/2/7
 */
#include <bits/stdc++.h>
using namespace std;

const int maxn = 101;
const int inf = 10001;

int e[maxn][maxn], dis[maxn], book[maxn], V, E;

void pf() {
    for (int i = 1; i <= V; i++) {
        for (int j = 1; j <= V; j++) {
            cout << e[i][j] << " ";
        }
        cout << endl;
    }
}

int main() {

    int t1, t2, t3, n;
    int minsub, min_e;

    //录入顶点和边的个数
    cin >> V >> E;

    //初始化邻接矩阵
    for (int i = 1; i <= V; i++)
        for (int j = 1; j <= V; j++)
            if ( i == j ) e[i][j] = 0; //自己到自己的距离为0
            else e[i][j] = inf; //否则为无穷大

    //录入边
    for (int i = 1; i <= E; i++) {
        cin >> t1 >> t2 >> t3;
        e[t1][t2] = t3;
    }

    //输入需要求最短路径的顶点
    cin >> n;

    //初始化dis数组,该数组表示n号顶点到其余顶点的初始距离
    for (int i = 1; i <= V; i++)
        dis[i] = e[n][i];

    //初始化book数组,用来标记该顶点有没有被使用过
    for (int i = 1; i <= V; i++)
        book[i] = 0;
    book[n] = 1;

    //Dijkstra算法核心语句
    for (int i = 1; i <= V - 1; i++) {
        //找到离顶点n最近的点
        min_e = inf;
        for (int j = 1; j <= V; j++) {
            if ( book[j] == 0 && dis[j] < min_e ) {
                min_e = dis[j];
                minsub = j;
            }
        }
        book[minsub] = 1;
        for (int j = 1; j <= V; j++) {
            if ( dis[j] > dis[minsub] + e[minsub][j] )
                dis[j] = dis[minsub] + e[minsub][j];
        }
    }

    //打印顶点n到各个顶点的最短路径
    for (int i = 1; i <= V; i++)
        cout << dis[i] << " ";
    /**
    6 9
    1 2 1
    1 3 12
    2 3 9
    2 4 3
    3 5 5
    4 3 4
    4 5 13
    4 6 15
    5 6 4
    1
    */
    return 0;
}
Bell-man:
/*
 *最短路径---Bellman(表男)算法
 *2018/2/7
 */
#include <bits/stdc++.h>
using namespace std;

const int maxe = 1001, maxv = 1001, inf = 10001;
struct edge {
    int from, to, cost;
};

int dis[maxv], V, E;
edge e[maxe];

int main() {

    bool check = true; //用于判断是否需要继续松弛
    int n;

    //输入顶点与边的个数
    cin >> V >> E;

    //录入边
    for (int i = 1; i <= E; i++)
        cin >> e[i].from >> e[i].to >> e[i].cost;

    //输入要求最短路径的顶点
    cin >> n;

    //初始化dis数组
    for (int i = 1; i <= V; i++)
        dis[i] = inf;
    dis[n] = 0;

    //表男算法核心语句
    for (int i = 1; i <= V - 1 && check == true; i++) {
        check = false;
        for (int j = 1; j <= E; j++)
            if ( dis[e[j].to] > dis[e[j].from] + e[j].cost ) {
                cout << dis[e[j].to] << " " << dis[e[j].from] << " " << dis[e[j].cost] << endl;
                dis[e[j].to] = dis[e[j].from] + e[j].cost;
                check = true;
            }
    }

    //检测负权回路
    for (int i = 1; i <= E; i++)
        if ( dis[e[i].to] > dis[e[i].from] + e[i].cost ) {
            cout << "该图存在负权回路" << endl;
            break;
        }

    //输出结果
    for (int i= 1; i <= V; i++)
        cout << dis[i] << " ";


    return 0;

}

显然,Bellman算法是可以进行优化的,因为每一次实施松弛操作后,就会有一些顶点已经求得了其最短路,此后这些顶点的最短路的估计值就会一直保持不变,不再收到后续松弛操作的影响,但是每次仍需要判断是否需要松弛,所以浪费了时间.所以我们每次仅对最短路估计值发生变化了的顶点的所有出边执行松弛操作.



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值