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,时间复杂度为 ,空间复杂度为
//
// 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:适用于全源最短路问题
- 要求被求解图的大小不大于200个点,若超过该数字,该算法可能因为效率不够高而被判别超时
- 若原图并非由邻接矩阵给出时,我们设法将其转换当两个节点间有多余一条边,我们选择长度最小的边权值存入邻接阵
- Floy算法完成后,图中所有节点间的最短路都被确定
Dijkstra算法:单源最短路路径问题
- 初始化,集合 K 中加入结点 1 ,结点 1 到结点 1 的最短距离为 0 ,到其他结点为无穷
- 遍历与集合 K 中结点直接相连的边(U, V, C),U 属于 集合 K,V 不属于集合 K ,计算又结点 1 出发按照已经达到的最短路达到 U ,再由 U 经过该边到达 V 时的路径长度, 比较所有与集合 K 中直接相邻的非集合 K 结点该路径长度,其中路径长度最小的结点被确定为下一个最短路径确定的点,其最短路径长度即为这个路径长度,最后将该节点加入集合K
- 集合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;
}