題意:平面上有N個點。一個人要從左上角的點向右走,到右下角的點,然後再回到左上角的點。現在想讓這個人每個點到達一次,且走的總路程的距離最小。求出最小的距離。
思路:雙調旅行商問題。
因爲起點和中途點已知,我們可以把這個問題轉化成兩個人從左上角出發,分別不重複的到達其他點,最後在右下角的點匯合。
可以注意到,在這個過程中,兩個人位於的點,他們經過的點,這三個就可以描述他們的狀態。
定義dp[i][j]爲一個人在點i,一個人在點j,他們經過了前
但是該怎麼樣進行狀態轉移呢?注意到
所以狀態轉移方程是:
其中
邊界條件:
算法複雜度爲
代碼如下:
#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;
}