O(N^2)最短路径算法

O(N^2) shortest path algorithm

本文关键字:最短路径 算法      更新时间:2023-10-16

问题指出,我们有一组点及其坐标,我们必须找到最短路径,始终从(0,0)开始到达目的地,然后再返回到(,0),只经过一次所有中间点。

输入如下第一行是中间点的数量,第二行是目的地的坐标,然后是所有中间点的坐标。没有中间点具有相同的x坐标,并且每个中间点的x坐标小于目的地的x坐标。

5
6 5
1 1
2 3
3 2
4 4
5 3

我用编程语言C++实现了这个问题,但问题是我听不懂。我一步一步地经历了它,但我不明白它的作用。

#include <fstream>
#include <cmath>
#include <algorithm>
#include <limits>
using namespace std;
const double inf = numeric_limits<double>::max(); // an infinite number
double dist [205][205] = {0};    
double res  [205][205] = {0};
int N (0);

struct point {
double x,y;
point(int a,int b):x(a),y(b){} 
point(){}
}points[205];  //struct to store inbetween points
inline const bool operator < ( const point &a, const point &b ){
return a.x < b.x;
}
int main()
{
ifstream in  ("evripos.in");
ofstream out ("evripos.out");
in>>N;
N+=2;
int t1,t2;
points[0]= point(0,0);
// stores all points 
for(int i=1;i<N;++i){
in>>t1>>t2;
points[i]=point(t1,t2);
}               
in.close();
sort(points,points+N); // sorts all points according to their x coordinate
// creates a 2 dimensional array of the distances between all points
// called dist
for(int i=0;i<N;++i)
for(int j=0;j<N;++j){
dist [i][j]= sqrt( pow(points[i].x-points[j].x,2) + pow(points[i].y-points[j].y,2));;
res[i][j]=inf;
}                
// computes the result, using a 2 dimensional array called res
res[0][0]=0;
for(int i=0;i<N;++i)
for(int j=0;j<N;++j){
res[i+1][i]   = min (res[i+1][i],   res[i][j] + dist[j][i+1]);
res[i+1][j]   = min (res[i+1][j],   res[i][j] + dist[i][i+1]);
res[i+1][i+1] = min (res[i+1][i+1], res[i][j] + dist[i][i+1] + dist[i+1][j]);  
}     
out<<round(res[N-1][N-1])<<endl;       //stores the end result
out.close();
}

我发现这是一个动态编程问题,据我所知,整个逻辑都在这里

res[0][0]=0;
for(int i=0;i<N;++i)
for(int j=0;j<N;++j){
res[i+1][i]  = min (res[i+1][i],   res[i][j] + dist[j][i+1]);
res[i+1][j]  = min (res[i+1][j],   res[i][j] + dist[i][i+1]);
res[i+1][i+1]= min (res[i+1][i+1], res[i][j] + dist[i][i+1] + dist[i+1][j]);  
}

这背后的逻辑究竟是什么?动态编程是如何解决这个问题的?

这是Bitonic巡回赛的问题。你有一个城市列表,从0到N-1,你需要从城市0开始,穿过每个城市一次到达N-1,从N-1返回0。

为了解决这个问题,我们需要改变我们看待它的方式。想象一下,从城市0出发的不是一个人,而是两个人,他们每个人永远不会在同一个城市(除了0和N-1),他们都试图到达城市N-1。因此,如果我们加上第一个人

第二个人因此,我们有我们的int [][]res,其中res[i][j]意味着人一在城市i第二位于城市j的最小总距离。我们观察到这条线路

res[i+1][i]      = min (res[i+1][i],   res[i][j] + dist[j][i+1]);

意味着从城市j开始的第二个人将前往城市i + 1。请注意,i + 1,而不是i,这将避免两个人在同一城市的情况。(还要注意,ij的作用可以互换)

类似的

res[i+1][j]    = min (res[i+1][j],   res[i][j] + dist[i][i+1]);

表示i开始前往城市i + 1的人员一

最后,假设目的地在i + 1,我们有

res[i+1][i+1]= min (res[i+1][i+1], res[i][j] + dist[i][i+1] + dist[i+1][j]);

注意:通过在外部for循环中将索引从i增加到i + 1,我们还保证在达到城市i + 1之前(通过个人一)已经达到从0到i的所有城市。

因此,问题的答案将在res[N-1][N-1]

希望这是帮助!