首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

POJ 2677 Tour:雙調歐幾里得旅行商問題 DP

     編輯:C++ 入門

POJ 2677 Tour:雙調歐幾里得旅行商問題 DP

給定 n 個點(x 坐標嚴格遞增),求最短閉合路徑,路徑先從最左點嚴格向右到最右點,再嚴格向左返回起點。即雙調路徑:x 坐標單調遞增後單調遞減。

DP 狀態定義

dp[i][j] (i > j) 表示:兩條路徑已覆蓋前 i 個點,一條路徑端點在第 i 點,另一條端點在第 j 點,當前總長度最小值。最終答案在 dp[n-1][j] + dist(j,n) + dist(n-1,n) 中取最小。

狀態轉移

  1. 擴展較長路徑(端點 i)→ i+1:dp[i+1][j] = min(dp[i+1][j], dp[i][j] + dist(i, i+1))
  2. 擴展較短路徑(端點 j)→ i+1:dp[i+1][i] = min(dp[i+1][i], dp[i][j] + dist(j, i+1))

初始:dp[1][1]=0, dp[2][1]=dist(1,2)。

完整代碼

double x[101], y[101];
double dp[101][101];
double dist(int a, int b) {
    return sqrt((x[a]-x[b])*(x[a]-x[b]) + (y[a]-y[b])*(y[a]-y[b]));
}

int main() {
    int n;
    while (scanf("%d", &n) == 1) {
        for (int i=1; i<=n; i++) scanf("%lf%lf", &x[i], &y[i]);
        const double INF = 1e9;
        for (int i=0; i<=n; i++) for (int j=0; j<=n; j++) dp[i][j] = INF;
        dp[1][1] = 0;
        dp[2][1] = dist(1,2);
        for (int i=2; i

關鍵點

  1. x 坐標嚴格遞增保證了「嚴格向右/向左」的幾何意義,DP 按索引順序自然滿足。
  2. 狀態 dp[i][j] 隱含:點 1..i 已全部訪問,兩條鏈端點為 i 和 j (j < i)。
  3. 轉移只需考慮將新點 i+1 接在兩條鏈末端的兩種方式。
  4. 最終閉合:兩條鏈端點分別為 n 和 j,補上 dist(j,n) 和 dist(n-1,n)(注意代碼中 dp[n][j] 已包含到 n-1 的路徑)。

複雜度

  • 狀態數 O(n²),n≤100(實際可能更大),轉移 O(1),總 O(n²) 極快。

幾何直觀

雙調路徑可視為兩條不相交鏈從左到右生長,最終在最右端會合再閉合。DP 精確捕捉了這一生長過程。

此題是「幾何 TSP 特例 → 多項式 DP」的經典案例,雙調性質將指數問題降為多項式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved