洛谷 P1523 旅行商简化版【线性dp+npc问题简化版】

原题链接:https://www.luogu.com.cn/problem/P1523

题目背景

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

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

题目描述

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

现在笛卡尔平面上有 (n≤1000) 个点,每个点的坐标为(x,y),-2^{31}<x,y<2^{31},且为整数),任意两点之间相互到达的代价为这两点的欧几里德距离,现要你编程求出最短 bitonic tour。

输入格式

第一行一个整数 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

解题思路:

这个题目是npc问题的简化版,也就是旅行商问题的简化版,

简化之后很像:P1006 [NOIP2008 提高组] 传纸条

这俩个题目的解题思想非常的像,但是又不完全相同,因为传纸条这个题目走的过程中间俩个人是允许走同一个点的,只是效益只计算一次,但是这个题目俩个人不允许走同一个点,首先我们利用类似传纸条这题的思想对题目进行类似转换,对于本题我们同样可以将来回走,变为俩个人一起从西边的点走到东边的点,这样就将原问题转换为了有俩个人从最西边的点都走到最东边的点,并且中间的每个点走且只走一次,这样我们就可以根据传纸条这题的思想来设计状态了,注意走的过程中由于不能走同样的点,所以走的过程中必然一个在前一个在后,我们还需要对于所有点按照横坐标从小到达排序。

状态定义

定义f[i][j]表示后面那个人走到i这个点,前面那个人走到j这个点,并且i<j,并且1~j之间的所有点都走过一次了的最短距离。

初始化

由于必须从西往东依次走过每一个点,我们最开始一定后面那个人在1号点,前面那个人在2号点,所以初始化为f[1][2]=d[1][2]

状态转移

当前i在后面,j在前面,1~j之间的所有点都已经走过了,接下来要走的点是j+1,那么存在俩种情况

(1)让j走到j+1,i暂时不动

(2)让i走到j+1,j暂时不动,会导致i走到j前面,为了保证前后性,我们交换i,j的位置

j走到j+1,i暂时不动

  • f[i][j + 1] = min(f[i][j + 1], f[i][j] + d[j][j + 1]);

i走到j+1,j暂时不动,并且需要交换i,j位置,原本i变为j+1,j还是j,现在交换变为i变为j,j变为j+1,交换位置才能保证前面那个仍然在前面,后面那个也仍然在后面。

  • f[j][j + 1] = min(f[j][j + 1], f[i][j] + d[i][j + 1]);

最终答案

最后一步一定是前面那个人已经到达了n号点,后面那个人可以在中间的任意一个点,后面那个人还没有到达终点,然后后面那个人走到n号点(终点),所以答案就是所有的min(f[i][n]+d[i][n])(1<=i<n)

时间复杂度:第一维枚举后面那个人当前所在点,时间为O(n),第二维枚举前面那个人当前所在点,时间为O(n),最终时间复杂度为O(n^2),n=1000,最终时间就是1e6,这个时间复杂度是肯定可以过的。

空间复杂度:俩个数组都是二维,空间复杂度为O(n^2)。

cpp代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>using namespace std;const int N = 1010;int n;
struct points
{double x, y;
} a[N]; // 存储所有点的坐标
double f[N][N], d[N][N];double get_distance(points u, points v) // 计算俩点之间的距离
{double dx = u.x - v.x, dy = u.y - v.y;return sqrt(dx * dx + dy * dy);
}
int main()
{cin >> n;for (int i = 1; i <= n; i++)scanf("%lf%lf", &a[i].x, &a[i].y);// 按照横坐标从小到达排序sort(a + 1, a + 1 + n, [&](points A, points B){ return A.x < B.x; });// 初始化距离数组d和dp数组ffor (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++){d[i][j] = d[j][i] = get_distance(a[i], a[j]);f[i][j] = 1e30;}// 初始时走在后面的那个人在1号点,走在前面的那个人在2号点,由于必须是从习往东一次走每个点,所以最开始俩人必然在1,2号点f[1][2] = d[1][2];for (int i = 1; i < n; i++)for (int j = i + 1; j <= n; j++) // 前面那个人要在后面那个人前面,所以这里从i+1开始枚举{/*当前i在后面,j在前面,1~j之间的所有点都已经走过了,接下来要走的点是j+1,那么存在俩种情况(1)让j走到j+1,i暂时不动(2)让i走到j+1,j暂时不动*/// j走到j+1,i暂时不动f[i][j + 1] = min(f[i][j + 1], f[i][j] + d[j][j + 1]);// i走到j+1,j暂时不动f[j][j + 1] = min(f[j][j + 1], f[i][j] + d[i][j + 1]);}/*最后一步一定是前面那个人已经到达了n号点,后面那个人可以在中间的任意一个点,后面那个人还没有到达终点,然后后面那个人走到n号点(终点),所以答案就是所有的min(f[i][n]+d[i][n]) (1<=i<n)*/double ans = 1e30;for (int i = 1; i < n; i++)ans = min(ans, f[i][n] + d[i][n]);printf("%.2lf\n", ans);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/626698.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二叉树(完全二叉树,满二叉树,二叉树的特性,遍历方式,根据遍历方式画出完整的二叉树图相关例题)

目录 基本概念 一、二叉树&#xff08;满二叉树&#xff0c;完全二叉树&#xff09; 二、二叉树的特性 1、若规定根节点的层数为1&#xff0c;则一棵非空二叉树的第i层最多有2^(i-1) 个节点&#xff08;i>0&#xff09; 2、若规定只有根节点的二叉树的深度为1&#xff0…

人力资源智能化管理项目(day01:基础架构拆解)

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 一、基础架构拆解 1.拉取模板代码 git clone GitHub - PanJiaChen/vue-admin-template: a vue2.0 minimal admin template 项目名 2.core-js…

使用WAF防御网络上的隐蔽威胁之SQL注入攻击

SQL注入攻击是一种普遍存在且危害巨大的网络安全威胁&#xff0c;它允许攻击者通过执行恶意的SQL语句来操纵或破坏数据库。 这种攻击不仅能够读取敏感数据&#xff0c;还可能用于添加、修改或删除数据库中的记录。因此&#xff0c;了解SQL注入攻击的机制及其防御策略对于保护网…

6.3.1认识Camtasia4(1)

6.3.1认识Camtasia4 安装完Camtasia4(本书使用Camtasia4.0.1版本)后&#xff0c;单击【开始】|【程序】|【Camtasia Studio 4】|【Camtasia Studio】&#xff0c;启动Camtasia Studio&#xff0c;启动后界面如图6-3-1所示。 图6-3-1 Camtasia Studio界面 Camtasia Studio窗口中…

打印的前后顺序

面试题经常会有 <script>console.log(1)setTimeout(function(){console.log(2)})console.log(3)let pnew Promise((resolve,reject) >{console.log(4)resloved(hhhhhh)})p.then(res >{console.log(res)console.log(5)},res >{console.log(7)})console.log(6)&l…

Git版本控制——分支

分支 几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着可以把工作从开发主线上分离开来进行重大的Bug修改、开发新的功能&#xff0c;以免影响开发主线。 查看本地分支 git branch创建本地分支 git branch 分支名切换分支(checkout) git checkout 分支名创建…

Python源码26:海龟画图turtle画向日葵

---------------turtle源码集合--------------- Python教程43&#xff1a;海龟画图turtle画小樱魔法阵 Python教程42&#xff1a;海龟画图turtle画海绵宝宝 Python教程41&#xff1a;海龟画图turtle画蜡笔小新 Python教程40&#xff1a;使用turtle画一只杰瑞 Python教程39…

萌宠宠物用品商城设计与制作-计算机毕业设计源码79718

摘要 在社会快速发展的影响下&#xff0c;宠物商城继续发展&#xff0c;大大增加了宠物用品的数量、多样性、质量等等的要求&#xff0c;使宠物用品商城的管理和运营比过去十年更加困难。依照这一现实为基础&#xff0c;设计一个快捷而又方便的萌宠宠物用品商城是一项十分重要并…

通过旋转机械臂,将机械臂上相机拍摄图像的任意点移动至图像中心的方法

计算原理 角度计算 相机CCD大小固定&#xff0c;即相机成像平面大小固定&#xff0c;相机视场角(FOV)仅由相机焦距F决定&#xff1b; 因此&#xff0c;定焦相机的FOV大小固定&#xff0c;通过上图可以看出相机视场角的计算公式为&#xff1a; FOV 2*atan&#xff08;w/2f&…

四、任意文件读取漏洞

一、介绍 解释&#xff1a;任意文件读取漏洞就其本身来说就是&#xff0c;攻击者绕过网站防御者设置的防御&#xff0c;读取到了正常使用者不应该读取到的内容。网站开发者使用不同的语言&#xff0c;任意文件读取漏洞利用方式就不同。 二、不同开发语言的不同漏洞点 1.PHP …

编译与链接(C/C++)

在C/C中关于代码的运行需要经过.c文件到.exe文件&#xff0c;而其中走过这些步骤这需要对原始的.c文件进行编译与链接。对于编译与链接主要构成了翻译环境&#xff0c;经过翻译环境之后生成.exe文件&#xff0c;然后在通过运行环境输出对应的结果。本篇主要讲解编译与链接。 以…

ElasticSearch扫盲概念篇[ES系列] - 第500篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 E…

KT148A语音芯片智能锁扩展语音地址以及如何支持大量小文件的打包

一、语音芯片应用于智能锁的需求 智能锁的语音播放需求中&#xff0c;有很多需要多国语言合并在一起的需求 其中语音文件数多&#xff0c;并且每个语音文件小的特点 如果使用OTP的语音芯片&#xff0c;就很麻烦&#xff0c;因为用户不可烧录&#xff0c;调试也很繁琐 同时大…

算法竞赛备赛进阶之数位DP训练

数位DP的思想就是对每一位进行DP&#xff0c;计算时记忆化每一位可以有的状态&#xff0c;其作用是减少运算时间&#xff0c;避免重复计算。 数位DP是一种计数用的DP&#xff0c;一般就是要统计一个区间[A,B]内满足一些条件数的个数。 以1e9甚至1e18、1e100的问题为例&#x…

YOLOv8改进 | 主干篇 | EfficientViT高效的特征提取网络完爆MobileNet系列(轻量化网络结构)

一、本文介绍 本文给大家带来的改进机制是主干网络,一个名字EfficientViT的特征提取网络(和之前发布的只是同名但不是同一个),其基本原理是提升视觉变换器在高效处理高分辨率视觉任务的能力。它采用了创新的建筑模块设计,包括三明治布局和级联群组注意力模块。其是一种高效率…

【ELK 学习】ElasticSearch

ELK&#xff1a;ElasticSearch存储&#xff0c;Logstash收集&#xff0c;Kibana展示 版本较多&#xff0c;使用时需要版本匹配&#xff0c;还需要和mysql版本匹配&#xff08;elastic官网给了版本对应关系&#xff09; 本次使用的版本es6.8.12 filebeat 轻量级的数据收集工具 …

多视图多标签学习

一、多视图学习 多视图学习又称多视角学习&#xff0c;在实际应用问题中&#xff0c;对于同一事物可以从多种不同的途径或不同的角度进行描述&#xff0c;这些不同的描述构成了事物的多个视图。例如&#xff1a;在与人们生活息息相关的互联网中&#xff0c;网页数据既可以用网…

C++ 设计模式之享元模式

【声明】本题目来源于卡码网&#xff08;题目页面 (kamacoder.com)&#xff09; 【提示&#xff1a;如果不想看文字介绍&#xff0c;可以直接跳转到C编码部分】 【简介】什么是享元模式 -- 可重复使用 享元模式是⼀种结构型设计模式&#xff0c;在享元模式中&#xff0c;对象被…

我记不住的那些位操作bitwise(一)

背景&#xff1a; 最近在看底层的一些知识内容&#xff0c;其中有一些位操作&#xff0c;所以想复习并记录一下。 一、或 或&#xff1a; 0 | 1 1 及 1 | 1 1 但是无法区分这两种情况(1. 一个是false&#xff0c;另一个是true&#xff1b; 2. 这两个都是true) 在C语…

PDF控件Spire.PDF for .NET【安全】演示:更改 PDF 文档的安全权限

当您使用密码保护 PDF 文档时&#xff0c;您可以选择指定一组权限。权限决定用户如何与文件交互。例如&#xff0c;您可以对文档应用权限以禁止用户打印或使用剪切和粘贴操作。本文演示如何在C# 和 VB.NET中使用Spire.PDF for .NET更改 PDF 文档的安全权限。 Spire.PDF for .N…