【题目背景】
欧几里德旅行商(Euclidean Traveling Salesman)问题也就是货郎担问题一直是困扰全世界数学家、计算机学家的著名问题。现有的算法都没有办法在确定型机器上在多项式时间内求出最优解,但是有办法在多项式时间内求出一个较优解。
为了简化问题,而且保证能在多项式时间内求出最优解,J.L.Bentley提出了一种叫做bitonic tour的哈密尔顿环游。它的要求是任意两点(a,b)之间的相互到达的代价dist(a,b)=dist(b,a)且任意两点之间可以相互到达,并且环游的路线只能是从最西端单向到最东端,再单项返回最西端,并且是一个哈密尔顿回路。
【问题描述】
著名的NPC难题的简化版本
现在笛卡尔平面上有n(n<=1000)个点,每个点的坐标为(x,y)(-2^31 < x,y<2^31,且为整数),任意两点之间相互到达的代价为这两点的欧几里德距离,现要你编程求出最短bitonic tour。 注意:任意两点X不相同。
第一行一个整数n
接下来n行,每行两个整数x,y,表示某个点的坐标。
输入中保证没有重复的两点,
保证最西端和最东端都只有一个点。
一行,即最短回路的长度,保留2位小数
7 0 6 1 0 2 3 5 4 6 1 7 5 8 2
25.58
平面内给出 n 个点,记横坐标最小的点为 A,最大的点为 B,现在小Y想要知道在每个点经过一次(A 点两次)的情况下从 A 走到 B,再回到 A 的最短路径。但他是个强迫症患者,他有许多奇奇怪怪的要求与限制条件:
1.从 A 走到 B 时,只能由横坐标小的点走到大的点。
2.由 B 回到 A 时,只能由横坐标大的点走到小的点。
3.有两个特殊点 b1 和 b2, b1 在 0 到 n-1 的路上,b2 在 n-1 到 0 的路上。
请你帮他解决这个问题助他治疗吧!
第一行三个整数 n,b1,b2,( 0 < b1,b2 < n-1 且 b1 <> b2)。n 表示点数,从 0 到 n-1 编号,b1 和 b2 为两个特殊点的编号。
以下 n 行,每行两个整数 x、y 表示该点的坐标(0 <= x,y <= 2000),从 0 号点顺序给出。Doctor Gao为了方便他的治疗,已经将给出的点按 x 增序排好了。
输出仅一行,即最短路径长度(精确到小数点后面 2 位)
5 1 3 1 3 3 4 4 1 7 5 8 3
18.18
【样例解释】
最短路径:0->1->4->3->2->0
【数据范围】
20%的数据n<=20
60%的数据n<=300
100%的数据n<=1000
对于所有数据x,y,b1,b2如题目描述.
两道题类似,路径相关的dp,也算得上一个模型吧,但二者略有些不同。
先说旅行商简版,f[i][j]表示i->1->j的路径(之间的所有点都会走一遍),因为是回路,所以我们只需考虑i>j的情况:
1、对于j
2、对于j=i-1,与i相邻的可能是1~i-2中的任意一个
3、对于j=i,与i相邻的可能是1~i-1中的任意一个
(然而我的代码是考虑的i>=j,k属于1~j更新,不知道为什么是对的,感觉正确写法应该是最后来特判,但显然下面一种递推方法更优秀~ ~)
对于简单路径这道题,因为有特殊点,上述简单回路的做法转移就不那么好想了(我是想不出来,果断co标)。好菜= =
f[i][j]表示从i出发走到1,再从1走到j的最短路径,乍一看更上面没有什么区别,实际需要慢慢感受,转移就很好想了:
f[i+1][j]=min{f[i+1][j],f[i][j]+dist[i][i+1]}
f[i][j+1]=min{f[i][j+1],f[i][j]+dist[j][j+1]}
//旅行商
#include
using namespace std;
const int Maxn=1005;
#define int long long
struct Local{
int x,y;
bool operator <(const Local&A) const {
return x
//简单路径
#include
using namespace std;
const int Maxn=1005;
#define int long long
struct Local{
int x,y;
bool operator <(const Local&A) const {
return x