旅行商简化版

背景 Background 

       欧几里德旅行商(Euclidean Traveling Salesman)问题也就是货郎担问题一直是困扰全世界数学家、计算机学家的著名问题。现有的算法都没有办法在确定型机器上在多项式时间内求出最优解,但是有办法在多项式时间内求出一个较优解。

 

为了简化问题,而且保证能在多项式时间内求出最优解,J.L.Bentley提出了一种叫做bitonic tour的哈密尔顿环游。它的要求是任意两点(a,b)之间的相互到达的代价dist(a,b)=dist(b,a)且任意两点之间可以相互到达,并且环游的路线只能是从最西端单向到最东端,再单项返回最西端,并且是一个哈密尔顿回路。

描述 Description  

       著名的NPC难题的简化版本

 

现在笛卡尔平面上有n(n<=1000)个点,每个点的坐标为(x,y)(-2^31<x,y<2^31,且为整数),任意两点之间相互到达的代价为这两点的欧几里德距离,现要你编程求出最短bitonic tour。

输入格式 Input Format

       第一行一个整数n

 

接下来n行,每行两个整数x,y,表示某个点的坐标。

 

输入中保证没有重复的两点,

保证最西端和最东端都只有一个点。

输出格式 Output Format    

      一行,即最短回路的长度,保留2位小数。

 

 

 

非常难想到的DP.

f[i][j] 表示第一个人走到第 i 点,第二个人走到第 j 个点。

因为 f[i][j] 与 f[j][i] 轮换对称, 为避免重复, 规定 i 恒大于 j.

若 j+1=i  f[i][j]=min(f[1~j-1][j]+dis(1~j-1,j)); f[j][1~j-1] 与 f[1~j-1][j] 对称。

若 j+1<i  f[i][j]=f[i-1][j]+dis(i-1,i);

 

另外 1e24 表示 10的24次方。

 

 1 #include<iostream>
 2 #include<math.h>
 3 #include<stdio.h> 
 4 //#include<fstream> 
 5 using namespace std;
 6 //ifstream fin("cin.in"); 
 7 
 8 int n;
 9 double f[1001][1001];
10 double d[1001][1001];
11 double x[1001],y[1001]; 
12 
13 void Qsort(int left,int right){
14      if(left>=right) return ;
15      int i=left,j=right;double mid=x[(left+right)>>1];
16      while(i<=j)
17      {
18        while(x[i]<mid) i++;
19        while(x[j]>mid) j--;
20        if(i<=j)
21        {
22          swap(x[i],x[j]);
23          swap(y[i],y[j]);
24          i++;j--; 
25                } 
26                 } 
27      Qsort(left,j);
28      Qsort(i,right); 
29      } 
30 
31 int main()
32 {
33     cin>>n;
34     for(int i=1;i<=n;++i)
35     cin>>x[i]>>y[i];
36     
37     Qsort(1,n); 
38     
39     for(int i=1;i<=n;++i)
40     for(int j=i+1;j<=n;++j)
41     d[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
42     
43     for(int i=1;i<=n;++i)
44     for(int j=1;j<=n;++j)
45     f[i][j]=1e24;
46      
47     f[2][1]=d[1][2]; 
48     for(int i=3;i<=n;++i)
49     for(int j=1;j<i;++j)
50     if(j+1<i) f[i][j]=f[i-1][j]+d[i-1][i];
51     else
52     {
53       for(int k=1;k<j;++k)
54       f[i][j]=min(f[i][j],f[j][k]+d[k][i]);   
55         } 
56              
57     printf("%.2lf\n",f[n][n-1]+d[n-1][n]); 
58     return 0; 
59     
60     } 

 

posted on 2012-08-05 15:48  怡红公子  阅读(631)  评论(0编辑  收藏  举报