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

1347 Tour:雙調歐幾里得旅行商問題動態規劃解法

     編輯:C++ 入門

問題描述

平面 n 點,求最短閉合雙調旅程:從最左點嚴格左→右至最右點,再嚴格右→左返回起點。點按 x 座標排序後,動態規劃 O(n²) 求解。

DP 狀態與轉移

設點按 x 升序編號 1..n。dp[i][j] (i > j) 表示兩條路徑分別到達 i 和 j,且已覆蓋 1..i 所有點的最小長度。其中一條路徑必在 i(最右),另一條在 j。

  • 情況 1:i 与 i-1 相連(兩條路徑端點分別為 i, j,j < i-1)
    dp[i][j] = dp[i-1][j] + dist(i, i-1)
  • 情況 2:i 与 j 相連(兩條路徑端點合併為 i, i-1)
    dp[i][i-1] = min(dp[i][i-1], dp[i-1][j] + dist(j, i)) 對所有 j < i-1 取最小

答案:min(dp[n][n-1] + dist(n-1,n), min_{j

代碼實現

#include <stdio.h>
#include <math.h>
#include <algorithm>
#define INF 1e20
const int N = 105;
int n; double x[N], y[N], dp[N][N];
double dis(int i, int j) {
    return sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]));
}
int main() {
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; i++) scanf("%lf%lf", &x[i], &y[i]);
        for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) dp[i][j] = INF;
        dp[2][1] = dis(2, 1);
        for (int i = 3; i <= n; i++) {
            dp[i][i-1] = INF;
            for (int j = 1; j < i-1; j++) {
                dp[i][j] = dp[i-1][j] + dis(i, i-1);
                dp[i][i-1] = std::min(dp[i][i-1], dp[i-1][j] + dis(j, i));
            }
        }
        double ans = dp[n][n-1] + dis(n-1, n);
        for (int j = 1; j < n-1; j++) ans = std::min(ans, dp[n][j] + dis(j, n));
        printf("%.2lf\n", ans);
    }
    return 0;
}

關鍵點

  • 預先按 x 排序(輸入可能已排序)。
  • DP 邊界:dp[2][1] 為兩點直連。
  • 雙調性保證無交叉,最優子結構成立。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved