UVA 1347 Tour 雙調旅行商

題意:平面上有N個點。一個人要從左上角的點向右走,到右下角的點,然後再回到左上角的點。現在想讓這個人每個點到達一次,且走的總路程的距離最小。求出最小的距離。
思路:雙調旅行商問題。
因爲起點和中途點已知,我們可以把這個問題轉化成兩個人從左上角出發,分別不重複的到達其他點,最後在右下角的點匯合。
可以注意到,在這個過程中,兩個人位於的點,他們經過的點,這三個就可以描述他們的狀態。
定義dp[i][j]爲一個人在點i,一個人在點j,他們經過了前max(i,j)  個城市,因爲兩個人的順序可以發生變化,我們令ij  是不會影響狀態的。
但是該怎麼樣進行狀態轉移呢?注意到dp[i][j]  表示他們已經走完了前i個城市,那爲了保持定義,我們必須下一個狀態走完前i+1個城市。但是由兩個人中的誰去呢?這個需要進行決策。
所以狀態轉移方程是:

dp[i][j]=min(dp[i+1][j]+d[i][i+1],dp[i+1][i]+d[j][i+1]),ij 

其中d[i][j]  表示第i個點和第j個點之間的距離。
邊界條件:
dp[n][j]=d[j][n] 

算法複雜度爲Θ(n 2 ). 
代碼如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

const int MAX = 1010;

int x[MAX],y[MAX];
double d[MAX][MAX];
double dp[MAX][MAX];

int main(void)
{
    //freopen("input.txt","r",stdin);
    int N;
    while(scanf("%d",&N) != EOF){
        for(int i = 1; i <= N; ++i)
            scanf("%d%d",&x[i],&y[i]);
        for(int i = 1; i <= N; ++i){
            for(int j = 1; j < i; ++j){
                double dx = x[i]-x[j];
                double dy = y[i]-y[j];
                d[i][j] = d[j][i] = sqrt(dx*dx+dy*dy);
            }
            d[i][i] = 0.0;
        }
        for(int i = 1; i <= N; ++i)
            dp[N][i] = d[i][N];
        for(int i = N - 1; i >= 1; --i)
            for(int j = 1; j <= i; ++j)
                dp[i][j] = min(dp[i+1][j] + d[i][i+1],dp[i+1][i] + d[j][i+1]);
        printf("%.2f\n",dp[1][1]);
    }
    return 0;
}
發佈了283 篇原創文章 · 獲贊 4 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章