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

时间:2014-01-19 14:44:31

标签: c++ algorithm dynamic-programming

问题表明我们有一组带有坐标的点,我们必须找到总是在(0,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]);  
  }

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

1 个答案:

答案 0 :(得分:2)

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

为了解决这个问题,我们需要改变我们看待它的方式。想象一下,没有一个,但两个人从城市0开始,他们每个人永远不会在同一个城市(0和N-1除外),他们都试图到达城市N-1。因此,如果我们添加 Person one Person two 所采用的路径,我们就可以得到原始问题的答案。

所以,我们有int [][]resres[i][j]表示第一人在城市i第二人<的最小总距离< / em>在城市j。我们观察到这一行

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

表示从城市j开始的 Person two 将转到城市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]);

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

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

希望有帮助!