第二十天:最短路径

Floyd思路

设 ans[k][i][j] 为结点 i 到结点 j 允许经过编号小于 k 的结点时其最短路径长度,ans[0][i][j]相当于edge[i][j],下完成求解

for(int k = 1;k <= n;k++){
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			if(ank[k - 1][i][k] == 10000 || ank[k - 1][k][j] == 10000){
				ans[k][i][j] = ans[k - 1][i][j];
				continue;
				}
			if(ank[k - 1][i][j] == 10000 || ank[k - 1][i][k] + ank[k - 1][k][j] < ank[k - 1][i][j])
				ank[k][i][j] = ank[k - 1][i][k] + ank[k - 1][k][j];
			else
				ank[k][i][j] = ank[k - 1][i][j];
			}
		}
	}

即可得所要求得ab间的最短路径,为ans[n][a][b]

TIPS

直接在二维数组上保持更新,并不会影响到那次更新中其他值得判定

for(int k = 1;k <= n;k++){
	for(int i = 1;i <= n;i++){
		for(int j = 1; j <= n;j++){
			if(ans[i][k] == 10000 || ans[k][j] == 10000)
				continue;
			if(ans[i][j] == 10000 || ans[i][k] + ans[k][j] < ans[i][j])
				ans[i][j] = ans[i][k] + ans[k][j];
			}
		}
	}

T1

最短路
时间限制:1 秒
内存限制:128 兆
特殊判题:否

题目描述: 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的 t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的! 所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

输入:输入包括多组数据。 每组数据第一行是两个整数N、 M (N<=100, M<=10000) , N 表示成都的大街上有几个路口,标号为 1 的路口是商店所在地,标号为 N 的路口是赛场所在地,M 则表示在成都有几条路。N=M=0 表示输入结束。接下来M 行,每行包括 3 个整数 A,B,C(1<=A,B<=N,1<=C<=1000) ,表示在路口 A 与路口 B 之间有一条路,我们的工作人员需要 C 分钟的时间走过这条路。输入保证至少存在 1 条商店到赛场的路线。
当输入为两个 0 时,输入结束。

输出: 对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间。

样例输入:
2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

样例输出:
3
2

Floyd算法主要包括一个三重循环,每重循环循环次数为N,时间复杂度为 O ( N 3 ) O(N^3) ,空间复杂度为 O ( N 2 ) O(N^2)

//
//  main.cpp
//  ShopRoad
//
//  Created by Apple on 2019/8/24.
//  Copyright © 2019 Apple_Lance. All rights reserved.
//

#include <iostream>
#include <stdio.h>
using namespace std;
int ans[101][101];

void printMax(int n){
    for(int i = 1; i <= n;i++){
        for(int j = 1; j <= n;j++)
            printf("%d ", ans[i][j]);
        printf("\n");
    }
    printf("\n");
}

int main(int argc, const char * argv[]) {
    // insert code here...
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF){
        if(m == 0 && n == 0)
            break;
        for(int i = 1;i <= n;i++){
            for(int j = 1;j <= n;j++)
                ans[i][j] = -1;
            ans[i][i] = 0;
        }
        while(m--){
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            ans[a][b] = ans[b][a] = c;
        }
        for(int k = 1;k <= n;k++){
            for(int i = 1;i <= n;i++){
                for(int j = 1;j <= n;j++){
                    if(ans[i][k] == -1 || ans[k][j] == -1)
                        continue;
                    if(ans[i][j] == -1 || ans[i][k] + ans[k][j] < ans[i][j])
                        ans[i][j] = ans[i][k] + ans[k][j];
                }
            }
        }
        printf("%d", ans[1][n]);
        
    }
    return 0;
}
Attention:适用于全源最短路问题
  1. 要求被求解图的大小不大于200个点,若超过该数字,该算法可能因为效率不够高而被判别超时
  2. 若原图并非由邻接矩阵给出时,我们设法将其转换当两个节点间有多余一条边,我们选择长度最小的边权值存入邻接阵
  3. Floy算法完成后,图中所有节点间的最短路都被确定

Dijkstra算法:单源最短路路径问题

  1. 初始化,集合 K 中加入结点 1 ,结点 1 到结点 1 的最短距离为 0 ,到其他结点为无穷
  2. 遍历与集合 K 中结点直接相连的边(U, V, C),U 属于 集合 K,V 不属于集合 K ,计算又结点 1 出发按照已经达到的最短路达到 U ,再由 U 经过该边到达 V 时的路径长度, 比较所有与集合 K 中直接相邻的非集合 K 结点该路径长度,其中路径长度最小的结点被确定为下一个最短路径确定的点,其最短路径长度即为这个路径长度,最后将该节点加入集合K
  3. 集合K包含所有结点;否则重复步骤二
//
//  main.cpp
//  DShopRoad
//
//  Created by Apple on 2019/8/24.
//  Copyright © 2019 Apple_Lance. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;

struct E{
    int next;
    int c;
};

vector<E> edge[101];
bool mark[101];
int dis[101];

int main(int argc, const char * argv[]) {
    // insert code here...
    int n, m;
    while(scanf("%d%d", &n, &m) != EOF){
        if(n == 0 && m == 0)
            break;
        for (int i = 1; i <= n; i++)
            edge[i].clear();
        while(m--){
            int a, b, c;
            scanf("%d%d%d", &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++){
            mark[i] = false;
            dis[i] = -1;
        }
        mark[1] = true;
        dis[1] = 0;
        int newP = 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])
                    continue;
                if(dis[t] == -1 || dis[t] > dis[newP] + c)
                    dis[t] = dis[newP] + c;
            }
            int min = 123123;
            for(int i = 1;i <= n;i++){
                if(mark[i] == true)
                    continue;
                if(dis[i] == -1)
                    continue;
                if(dis[i] < min){
                    min = dis[i];
                    newP = i;
                }
            }
            mark[newP] = true;
        }
        printf("%d\n", dis[n]);
    }
    return 0;
}

T2

最短路径问题

时间限制:1 秒
内存限制:128 兆
特殊判题:否

题目描述: 给你 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)

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

样例输入: 3 2 1 2 5 6 2 3 4 5 1 3 0 0
样例输出: 9 11

//
//  main.cpp
//  ShortestRoad
//
//  Created by Apple on 2019/8/25.
//  Copyright © 2019 Apple_Lance. All rights reserved.
//

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;

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

vector<E> edge[1001];
bool mark[1001];
int dis[1001];
int cost[1001];

int main(int argc, const char * argv[]) {
    // insert code here...
    int n, m;
    int S, T;
    while(scanf("%d%d", &n, &m) != EOF){
        if(n == 0 && m == 0)
            break;
        for(int i = 1;i <= n;i++)
            edge[i].clear();
        while(m--){
            int a, b, d, c;
            scanf("%d%d%d%d", &a, &b, &d, &c);
            E tmp;
            tmp.c = d;
            tmp.cost = c;
            tmp.next = b;
            edge[a].push_back(tmp);
            tmp.next = a;
            edge[b].push_back(tmp);
        }
        scanf("%d%d", &S, &T);
        for(int i = 1;i <= n;i++){
            mark[i] = false;
            dis[i] = -1;
            cost[i] = 0;
        }
        dis[S] = 0;
        mark[S] = true;
        int newP = S;
        for(int i = 1;i < n;i++){
            for(int j = 0;j<edge[i].size();j++){
                int t = edge[newP][j].next;
                int c = edge[newP][j].c;
                int co = edge[newP][j].cost;
                if(mark[t] == true)
                    continue;
                if(dis[t] == -1 || dis[newP] + c < dis[t] || dis[newP] + c == dis[t] && cost[newP] + co < cost[t]){
                    dis[t] = dis[newP] + c;
                    cost[t] = cost[newP] + co;
                }
            }
            int min = 123123;
            for(int j = 1;j <= n;j++){
                if(mark[j] == true)
                    continue;
                if(dis[j] == -1)
                    continue;
                if(dis[j] < min){
                    min = dis[j];
                    newP = j;
                }
            }
            mark[newP] = true;
        }
        printf("%d %d", dis[T], cost[T]);
    }
    return 0;
}
发布了182 篇原创文章 · 获赞 101 · 访问量 20万+

猜你喜欢

转载自blog.csdn.net/lancecrazy/article/details/100056379