学会了一道图的最短路径问题
一道图的最短路径问题
Description
天气逐渐变冷,年老体弱的越越鸟打算去南方某座温度适宜的城市过冬,但由于翅膀严重老化,最远飞行距离有限,请你为可怜的越越鸟计算飞行所需的最短距离,以让它能做好心理准备。
Input
输入包含多组测试数据。
每组输入第一行为两个正整数n(n<=20)和m(m<=n*(n-1)/2),n表示城市个数,m表示线段个数。(线段为两个城市间的连接线)
接下来m行,每行输入三个整数a,b,和l(l<=10^9),表示a市与b市之间存在一条线段,线段长度为l。(a与b不同)
每组最后一行输入两个整数x和y,表示问题:x为越越鸟现在所在的城市,y为越越鸟打算飞往过冬的城市。城市标号为1~n。
Output
对于每组输入,输出x市与y市之间的最短距离,如果x市与y市之间非连通,则输出“No path”。
Samples
input Copy
4 4 1 2 4 1 3 1 1 4 1 2 3 1 2 4
output Copy
3
Dijkstra
迪杰斯特拉算法是用来求一个顶点到其余各顶点的最短路径算法,正好适合这道题
思路
迪杰斯特拉算法中,我们要维护一个found数组,found[i]表示到i点的最短路径是否已经找到,还要维护一个distance数组,distance[i]表示到i点的最短路径。每次从未找到最短路径的点中,找出路径最短的点,然后标记为已找到,再从它出发,探索有没有到其他节点的路径,有路径且比当前的短,就更新distance数组
代码
#include"iostream"
using namespace std;
#define max 1000000000
int graph[50][50];
int find(int dis[], int s[],int n){
int min=max;
int minpos=-1;
for(int i=1; i <= n; i++){
if(dis[i] < min && s[i]==0){
min = dis[i];
minpos = i;
}
}
return minpos;
}
int main(){
int n,m;
while(cin>>n>>m) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
graph[i][j] = max;
}
}
for (int i = 1; i <= n; i++) {
graph[i][i] = 0;
}
while (m--) {
int a, b, l;
cin >> a >> b >> l;
graph[a][b] = graph[b][a] = l;
}
int x, y;
cin >> x >> y;
int dis[n + 1];
int s[n + 1];
for (int i = 1; i <= n; i++) {
dis[i] = graph[x][i];
s[i]=0;
}
int u;
s[x] = 1;
while (u = find(dis, s, n), u != -1) {
s[u] = 1;
for (int w = 1; w <= n; w++) {
if (dis[u] + graph[u][w] < dis[w]) {
dis[w] = dis[u] + graph[u][w];
}
}
}
if (dis[y] == max) {
cout << "No path" << endl;
} else {
cout << dis[y] << endl;
}
}
}
这个算法的时间复杂度是O(n^2)
Floyd算法
Floyd算法是求图中任意两点之间距离的算法
思路
Floyd算法就是每一次从邻接矩阵中选一个顶点,然后去矩阵中遍历两个顶点i,j,比较i->j的距离和i->k加上k->j的距离
Floyd算法比较暴力,十分好记
#include"iostream"
#include"set"
#include"vector"
#include"algorithm"
using namespace std;
int main(){
int n,m;
while(cin>>n>>m) {
vector<vector<int> > graph(n + 1, vector<int>(n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i != j)graph[i][j] = 1000000000;
else graph[i][j] = 0;
}
}
while (m--) {
int a, b, l;
cin >> a >> b >> l;
graph[a][b] = graph[b][a] = l;
}
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (graph[i][j] > graph[i][k] + graph[k][j]) {
graph[i][j] = graph[i][k] + graph[k][j];
}
}
}
}
int x, y;
cin >> x >> y;
if (graph[x][y] == 1000000000) {
cout << "No path" << endl;
} else {
cout << graph[x][y] << endl;
}
}
}
这三个for循环告诉我们,他的时间复杂度是O(n^3),虽然慢了点,但是好记呀。