TSP問題+例題


    題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=1217

    這道題是tsp板子題,不會做硬鋼了兩天,看了題解學了tsp,現在有點似懂非懂,簡單記錄一下.

    歐幾里得旅行商問題是對平面上給定的n個點確定一條連接各點的最短閉合旅程的問題,下圖a給出了7個點問題的解。這個問題的一般形式是NP完全的,故其解需要多於多項式的時間。

                 

                    

 


                     (a)                                                          (b)

     J.L.Bentley建議通過只考慮雙調旅程來簡化問題,這種旅程即為從最左點開始,嚴格地從左到右直至最右點,然后嚴格地從右到左直至出發點。b顯示了同樣7個點問題的最短雙調路線。在這種情況下,多項式時間的算法是可能的。

   描述一個確定最優雙調路線的O(n^2)時間的算法,可以假設任何兩點的x坐標都不相同。

 

 

將各個節點從左到右排序,編號為1,2,3,.....,n。對於任意的i和j(其中1<=i,j<=n)。

現在有兩條路徑A、B都是從點1出發,A走的路徑為1~ i ,B走的路徑為1~ j ,

即A、B有公共的起點,但途中沒有交叉點(即終點之前不存在 i=j ),終點可能重合(i=j),也可能不重合(i≠j),這取決與我們要求的問題。

令s=max(i,j),則從1到s所有的點一定在路徑A或者路徑B上,不會有遺漏的點.

對於特定的 i 和 j ,路徑A、B存在多種可能的走法,其中比有一種2條路徑的和最小的走法,我們把這2條路徑的和記為b[i,j];當i=j時,b[i,j]表示了從1到 i 的雙調TSP的解;當i=j=n時 b[i,j] 就表示了整個問題的最終解法。

我們可以采用DP(動態規划)求解

 



上圖表示對b[i,j]的遞推情況,開始時,顯然b[i,j]=0,而i=0或j=0也可以直接確定b[i,j]的值;

基於對稱的考慮,表的左下半部和右上半部的數值將完全相同,所以在生成表的時候可以不用考慮下半部分

如何求遞推?分一下幾種情況

① i > j (即圖的右上部分)

 



已知b[i,j] ,求b[i+1,j],只要將A直接延長到 i+1就行。

即 b[i+1,j] = b[i,j] + distance(i,i+1)

 

② i = j (對角線部分)

假設已知b[i,i],求b[i+1,i],可以想象,此時AB兩條路徑在終點 i 相交,因為現在我們要求A的終點為i+1,所以不得不把相交的AB在i點拆開。

 



事情沒那么簡單,拆開后,我們需要在路徑A找任意點u(0<=u<=i),使點u連接點i+1.

由於b[ u , j ] 是A路徑到u,B路徑到j,經過max(u,j)內所有點,所以b[ u , j ]+distance( i , u ) = b[ i , j ]

我們需要找到 min{ b[u,j] + distance(u, i+1)},即遍歷 b[1..i, j],剛好這是圖的左下部分,因為這個部分是和右上部分對稱的,所以可以直接利用右上部分的數據。

b[i+1,j] = min{ B[u,i] + w(u,i+1) }

③ 確定b[n,n],即確定最終的解。

前面 ①②部分已經可以把所有的點都走一次了,現在我們最后需要做的是,把AB路徑的頭連接起來。

那怎么連接才能讓AB路徑加起來最短呢?

前面我們說過: s=max(i,j),則從1到s所有的點一定在路徑A或者路徑B上,不會有遺漏的點

通過①②我們已經求出 1~s 點的所有數據。

也就是我們可以通過 min{ b[n,k] + distance(n,k)} 其中 1<=k<n 求出b[n,n];

b[n,n] =  min{ b[n,k] + distance(n,k)}

 

總結一下:

 b[i,j] = b[i-1,j] + distance(i-1,i) (j+1 < i ,藍色部分)

 b[i,j] = min{ B[u,i] + w(u,i+1) } (j+1 = i ,紅色部分)

b[n,n] =  min{ b[n,k] + distance(n,k)}  0<=k<n

 

轉自大佬博客:https://blog.csdn.net/qq742762377/article/details/85050040

 

 

 附加:想到一個問題,有人問我,我們既然可以從(0,0)遞推到(1,0),遞推到(2,0).......到(n,0) 為什么直接從(2,0)推到(2,1)呢?

   解釋一下,根據我們的定義在(2,0)的時候,一號點是已經走過了,所以如果我們要從(2,0)推(2,1)的話就會發生這樣的事情

 

 

這個代表(2,0),推到到(2,1)的時候就變成了這樣

這樣肯定不對啊,因為兩條路在1號點就相交了所以(2,1)只能根據(1,0)推出來

 

題目ac代碼:

#include<bits/stdc++.h>
using namespace std;
#define INT_MAX 0x73f3f3f
typedef struct W_W{
    int a;
    int b;
}miao;
miao x[1010];
double weight[1010][1010];
double dp[101][1010];
double jl(int a,int b){
    return sqrt((x[a].a-x[b].a)*(x[a].a-x[b].a)*1.0+(x[a].b-x[b].b)*(x[a].b-x[b].b)*1.0);
}
bool cmp(miao a,miao b){
    return a.a<b.a;
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++){
        scanf("%d %d",&x[i].a,&x[i].b);
        }
        sort(x,x+n,cmp);
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                dp[i][j]=-1.0;
                weight[i][j]=0.0;
            }
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(i==j){
                    weight[i][j]=0;
                }
                else{
                    weight[i][j]=jl(i,j);
                }
            }
        }
        dp[0][0]=0;
        dp[1][0]=weight[1][0];
        for(int i=2;i<n;i++){
            for(int j=0;j<i;j++){
                if(i!=j+1){
                    dp[i][j]=dp[i-1][j]+weight[i][i-1];
                }
                else{
                    double minn=INT_MAX;
                    for(int k=0;k<j;k++){
                        minn=min(minn,dp[j][k]+weight[i][k]);
                    }
                    dp[i][j]=minn;
                }
            }
        }
        double ans=INT_MAX;
        //printf("%d\n",dp[1][1]);
    //    for(int i=0;i<n;i++){
    //        for(int j=0;j<n;j++){
    //            printf("%.2lf ",dp[i][j]);
    //        }
    //        printf("\n");
    //    }
        for(int i=0;i<n-1;i++){
            ans=min(dp[n-1][i]+weight[n-1][i],ans);
        }
        printf("%.2f\n",ans);

    }
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM