• P1523 旅行商简化版, 路径dp


    P1523 旅行商简化版 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

    这是一道很有启发意义,代表性的难题

    题目背景

    欧几里德旅行商(Euclidean Traveling Salesman)问题也就是货郎担问题一直是困扰全世界数学家、计算机学家的著名问题。现有的算法都没有办法在确定型机器上在多项式时间内求出最优解,但是有办法在多项式时间内求出一个较优解。

    为了简化问题,而且保证能在多项式时间内求出最优解,J.L.Bentley 提出了一种叫做 bitonic tour 的哈密尔顿环游。它的要求是任意两点 (a,b) 之间的相互到达的代价 dist(a,b)=dist(b,a) 且任意两点之间可以相互到达,并且环游的路线只能是从最西端单向到最东端,再单项返回最西端,并且是一个哈密尔顿回路。

    题目描述

    本题为著名的 NPC 难题的简化版本。

    现在笛卡尔平面上有 n(n≤1000) 个点,每个点的坐标为(x,y),(−231

    输入格式

    第一行一个整数 n。

    接下来 n 行,每行两个整数 x,y,表示某个点的坐标。

    输入中保证没有重复的两点,保证最西端和最东端都只有一个点。

    输出格式

    一行,即最短回路的长度,保留 2 位小数。

    输入输出样例

    输入 #1复制

    7
    0 6
    1 0
    2 3
    5 4
    6 1
    7 5
    8 2
    

    输出 #1复制

    25.58
    

    说明/提示

    题目来源

    《算法导论(第二版)》 15-1

    解析:

    题目意思:给定一堆点,求从左到右两天不相交的路径(起点和终点除外)的最小权值和。

    将点按横坐标排序;将集合划分为 f[i][j] 两个不从不漏的子集,表示:第一条路经以第 i 个点为终点,第二条路径以第 j 个点为终点,且除起点外严格不相交的两条路经的权值的最小值。

    由于 f[i][j]==f[j][i],所以我们让 i>j;

    根据划分的含义,状态 f[i][j] 可由一下状态转移而来:
    当 i=j+1 时:f[j][k] (k=1,……,j-1);

    当 i>j+1 时:f[i-1][j];

    我是用的是顺推的方式,这里介绍一个更简洁的逆推的方法:题解 P1523 【旅行商简化版】 - 梦想家的憩息所 - 洛谷博客 (luogu.com.cn)

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. using namespace std;
    16. typedef long long LL;
    17. const int N = 1e3 + 5;
    18. const double inf = 1e50;
    19. int n;
    20. struct node {
    21. double x, y;
    22. }arr[N];
    23. double f[N][N];
    24. int cmp(const struct node& a, const struct node& b) {
    25. if (a.x == b.x)
    26. return a.y < b.y;
    27. return a.x < b.x;
    28. }
    29. double dist(int a, int b) {
    30. double ret = fabs(arr[a].x - arr[b].x) * fabs(arr[a].x - arr[b].x);
    31. ret += fabs(arr[a].y - arr[b].y) * fabs(arr[a].y - arr[b].y);
    32. return sqrt(ret);
    33. }
    34. int main() {
    35. scanf("%d", &n);
    36. for (int i = 1; i <= n; i++) {
    37. scanf("%lf%lf", &arr[i].x, &arr[i].y);
    38. }
    39. sort(arr + 1, arr + 1 + n, cmp);
    40. for (int i = 0; i <= n; i++) {
    41. for (int j = 0; j <= n; j++)
    42. f[i][j] = inf;
    43. }
    44. f[2][1] = dist(1, 2);
    45. for (int i = 3; i <= n; i++) {
    46. for (int j = 1; j <=i-1; j++) {
    47. if (i == j + 1) {
    48. for (int k = 1; k <=j-1; k++) {
    49. f[i][j] = min(f[i][j], f[j][k] + dist(k, i));
    50. }
    51. }
    52. else {
    53. f[i][j] = min(f[i][j], f[i - 1][j] + dist(i, i - 1));
    54. }
    55. }
    56. }
    57. double ans = inf;
    58. for (int i = 1; i <= n; i++) {
    59. ans = min(f[n][i] + dist(n, i), ans);
    60. }
    61. printf("%.2lf", ans);
    62. return 0;
    63. }

  • 相关阅读:
    安卓的分区一点有用知识:super、lpunpack、lpdump
    javaweb个人物品信息管理系统springboot+Ssm
    数据结构-------队列
    Ps:简单快速的主背分离方法
    代码随想录算法训练营第五十一天| 309.最佳买卖股票时机含冷冻期,714.买卖股票的最佳时机含手续费,总结
    详解csrf(跨站请求伪造)
    【Android】VirtualDisplay创建流程及原理
    3.28 OrCAD中怎么对元器件位号进行统一编号?OrCAD中怎么按页面的方式有规律地对元器件位号进行编排?
    配置Hive使用Spark执行引擎
    小程序商城开发注意事项与作用意义_OctShop
  • 原文地址:https://blog.csdn.net/Landing_on_Mars/article/details/134046027