算法学习--Day9

继上一次完成最小生成树后,这次我开始准备最短路径的程序。

最短路分为两种算法,第一个为Floyd算法,第二个为Dijkstra。

简单来说,Floyd是以点为参照对象,它使用三层循环求解当前图中所有点之间的最短距离。

也就是说,当他的循环处理结束后,你就可以从中找到任意两点之间的最短路径了。

他将大规模问题简化成为若干个子问题,并先对规模小的问题求解出最优值,之后利用规模小的问题的解去递推出大规模问题的解。

核心代码:

for(int i=1;i<=n;i++){
    for(int j=1;j<=n;j++){
        for(int k=1;k<=n;k++){
           if(ans[j][i]==-1 || ans[i][k]==-1) continue;
//这句话说明倘若我j-i-k中间有某条路是不通的,这个时候我就不能被更新,所以直接跳过就好
           if(ans[j][k]==-1 || ans[j][i]+ans[i][k]<ans[j][k]){  ans[j][k]= ans[j][i]+ans[i][k];}
//这句话用来更新最小值
}    
}
}         

下面我们看dijkstra算法。

题目描述

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入描述:

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(1<n<=1000, 0<m<100000, s != t)

输出描述:

输出 一行有两个数, 最短距离及其花费。
示例1

输入

复制
3 2
1 2 5 6
2 3 4 5
1 3
0 0

输出

复制
9 11
//
// Created by 陈平 on 2018/6/7.
//

#include "iostream"
#include "stdio.h"
#include "vector"
using namespace std;

struct E{
    int next;
    int c;
    int cost;

};
vector<E> edge[1001];
int dis[1001];
int cost[1001];
bool mark[1001];
int main(){
    int n,m;
    int s,t;
    while (scanf("%d%d",&n,&m)!=EOF){
        if(n==0 && m==n) break;
        for (int i = 1; i <=n ; ++i) {
            edge[i].clear();
        }
        while (m--){
            int a,b,c,cost;
            cin>>a>>b>>c>>cost;
            E tmp;
            tmp.c = c;
            tmp.cost = cost;
            tmp.next = b;
            edge[a].push_back(tmp);
            tmp.next = a;
            edge[b].push_back(tmp);
        }
        cin>>s>>t;
        for (int j = 1; j <=n ; ++j) {
            dis[j] = -1;
            mark[j] = false;
        }
        dis[s] = 0;
        cost[s] = 0;
        mark[s] = true;
        int newP = s;


        for (int k = 1; k <n ; ++k) {
            for (int i = 0; i <edge[newP].size() ; ++i) {

                int t = edge[newP][i].next;
                int c = edge[newP][i].c;
                int co = edge[newP][i].cost;
                if(mark[t]) continue;
                if (dis[t]==-1 || dis[t]>dis[newP] + c ||dis[t]==dis[newP] + c && cost[t]>cost[newP]+co ){
                    dis[t] = dis[newP] + c;
                    cost[t] = cost[newP] + co;
                }
            }

            int minn = 1000000;
            for (int j = 1; j <=n ; ++j) {

                if(mark[j]) continue;
                if(dis[j]==-1) continue;
                if(dis[j] < minn ){

                    minn = dis[j];
                    newP = j;

                }
            }
            mark[newP] = true;
        }

    cout<<dis[t]<<" "<<cost[t]<<endl;
    }
}

在写最短路的时候,我们要熟悉使用链表的写法,当数据量增多的时候,使用链表会使节省空间与时间。所以我们要在初始化的时候使用push_back函数把值push进去。而在处理的时候,我们需要分两步去找最优解。第一步为更新当前点集合所连接的点的长度数据。(因为上一步加入了另一个点后我们的长度还未更新)第二步为寻找未在当前集合并且是最短距离的点。(具体流程见我之前的一个博客——https://www.cnblogs.com/Pinging/p/7911169.html

猜你喜欢

转载自www.cnblogs.com/Pinging/p/9158775.html