ACM - 动态规划 - UVA 1347 Tour

UVA 1347 Tour

题解

题目大意:有 n 个点,给出点的 xy 坐标。找出一条经过所有点一次的回路,从最左边的点出发,严格向右走,到达最右点再严格向左,回到最左点。问最短路径距离是多少?

这题原始的问法是不加严格向左严格向右的边界条件,也即著名的旅行商问题(TSP 问题),原问题已经被证明是一个 NP 难的问题。但在此题的限制条件下,我们可以在多项式时间里解决该问题。

我们可以试着从最左边往右走,当准备经过一个点时,它只有两种可能,一是从左往右时经过该点,二是从右往左经过该点。我们可以直接将问题等价为:两个人都从最左边往最右边行走(x 坐标严格大),每个点都被经过且仅被一个人经过(除起点和终点,起点和终点被各自经过一次),使两条路径加和最短。

显然同一个 x 坐标的点的数量最多两个,如果有至少三个点会使得至少一个点不能被这两人经过(路径要求 x 坐标严格大),此时必定不能形成回路。

我们使用动态规划求解,令 dp[i][j] 表示点 1max(i,j) 全部走过,且两个人的当前位置分别是点 ij,还需要走多长的距离到达最右边(终点)。

状态转移方程

考虑状态 dp[i][j],由于此时点 1max(i,j) 全部走过,因此要达到此状态,只有两种可能,点 max(i,j)+1 由第一个人走,点 max(i,j)+1 由第二个人走。

dist(m1,m2) 函数表示点 m1 到 点 m2 的欧几里得距离。此时若 i>j

第一种情况表示为

dp[i][j]=dp[i+1][j]+dist(i,i+1)

第二种情况表示为

dp[i][j]=dp[i][i+1]+dist(i+1,j)

综上,写出状态转移方程:

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

我们再考虑边界的状态,边界如下

dp[n1][j]=dist(n1,n)+dist(n,j)

状态搜索方向

使用递归做状态搜索,此方法的另一种名称叫记忆化搜索,但我个人倾向于将记忆化搜索视为动态规划的递归实现(即使用递归用状态搜索)。

程序实现

使用 C++ 实现算法。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#define PII pair<int, int> 
#define INF 0x3f3f3f3f
using namespace std;

struct point
{
    double x;  // x 坐标
    double y;  // y 坐标
}ps[1005];

double dp[1005][1005];

double dist(int i, int j)
{
    return sqrt((ps[i].x - ps[j].x) * (ps[i].x - ps[j].x) +
                (ps[i].y - ps[j].y) * (ps[i].y - ps[j].y));
}

double fun(int i, int j)
{
    if (dp[i][j] > 0)
        return dp[i][j];
    return dp[i][j] = min(fun(i + 1, j) + dist(i, i + 1),
                          fun(i + 1, i) + dist(j, i + 1));
}

int main()
{
    int N = 1;
    while (cin >> N) {
        for (int i = 1; i <= N; ++i)
            cin >> ps[i].x >> ps[i].y;
        memset(dp, 0, sizeof(dp));
        for (int j = 1; j < N - 1; j++)
            dp[N - 1][j] = dist(N - 1, N) + dist(j, N);
        double ans = fun(1, 1);
        printf("%.2f\n", ans);
    }
    return 0;
}

posted on   Black_x  阅读(29)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示