P1523 旅行商简化版

题目背景

欧几里德旅行商(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。

输入输出格式

输入格式:

第一行一个整数n

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

输入中保证没有重复的两点,

保证最西端和最东端都只有一个点。

输出格式:

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

输入输出样例

输入样例#1:

7
0 6
1 0
2 3
5 4
6 1
7 5
8 2
输出样例#1:

25.58
 

分析:

下面提供两种方法,刷表法和填表法
 
1、刷表法
代码是从前往后刷表

【1】题意:旅行商问题,不过要求只能单向走,就是有n个地方,要求从西往东,到最东面的地方,在从东往西返回,经过每个点一次,求最短路径

【2】分析:由于有了方向的限制,这题不再是NP难题,我们可以假设有两个人一起从西往东走,走过的点不能重复,这样就有f[ i ][ j ]表示第一个人走到i,第二个人走到j 的最短路径,要求i<j,且0到j的点都被经过了,这样很容易想到,j+1的点不是被第一个人走,就是被第二个人走,所以有转移方程f[ i ][ j+1]=min{ f[ i ] [ j ]+d[ j ] [ j +1] } f[ j ] [ j+1 ]=min{ f[ i ][ j ]+d[ i ][ j+1 ] },第一个转移方程很容易理解,第二个方程可以这么理解,两个人可以指前面一个人,和后面一个人,当后面的人走到前面,当然就对换过来了,不影响结果

【3】最后,预处理f[ 0 ][ 1]还有扫描 一遍答案就行了,这题算是一类DP吧,思路挺有启发性的

 #include <cmath>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int mm=;
struct data
{
double x,y;
}g[mm];
double d[mm][mm],f[mm][mm];
int i,j,k,n;
bool cmp(const data &a,const data &b)
{
return a.x<b.x;
}
double mdis(const data &a, const data &b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
int main()
{
scanf("%d",&n);
for(i=;i<n;++i)
scanf("%lf%lf",&g[i].x,&g[i].y);
sort(g,g+n,cmp);
for(i=;i<n;++i)
for(j=i+;j<n;++j)
{
d[i][j]=mdis(g[i],g[j]);
f[i][j]=1e30;
}
f[][]=d[][];
for(i=;i<n;++i)
for(j=i+;j<n;++j)
{
f[i][j+]=min(f[i][j+],f[i][j]+d[j][j+]);
f[j][j+]=min(f[j][j+],f[i][j]+d[i][j+]);
}
double ans=1e30;
for(j=;j<n-;++j)
ans=min(ans,f[j][n-]+d[j][n-]);
printf("%.2lf\n",ans);
return ;
}

2、填表法

代码是从后往前填表

遍历一整个图, 从开始位置走到末尾,再走回开始位置,并且不能重复;

由于题目并没有对输入数据按X从小到大排序,所以先排序,然后预处理出每两个点之间的欧几里得距离。

f(i,j)表示 从 1->max(i,j) 已经全部遍历切没有重复的最短路;

那么可知F(i , j) = F(j , i); 于是就规定 i > j;

如果 i = n - 1; 那么就强行将j跳到末尾位置;f(i, j) = dis(i, n) + dis(j, n);

其余可知 f(i,j) = max ( f(i+1, j) + dis(i, i +1), f(i+1, i) + dis(j, i+1)) 原本应写成f(i, i+1), 但由于规定所以写成这样;

最终状态为f(2, 1);

接着就是naive的输出啦;

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
typedef long long Lovelive;
using namespace std; const int maxn = + ;
int n;
struct Node {
double x, y;
}node[maxn];
double dis[maxn][maxn], f[maxn][maxn]; bool cmp(Node a, Node b) {
return a.x < b.x;
} int main() {
scanf("%d",&n);
for(int i = ; i <= n; i++) scanf("%lf%lf",&node[i].x,&node[i].y);
sort(node+, node+n+, cmp);
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++)
dis[i][j] = sqrt((node[i].x-node[j].x)*(node[i].x-node[j].x) + (node[i].y-node[j].y)*(node[i].y-node[j].y)); for(int i = n-; i >= ; i--)
for(int j = ; j < i; j++)
if(i == n-) f[i][j] = dis[i][n] + dis[j][n];
else f[i][j] = min (f[i+][j] + dis[i][i+], f[i+][i] + dis[j][i+]);
printf("%.2lf",f[][] + dis[][]);
return ;
}
 
 
 
 
 

P1523 旅行商简化版的更多相关文章

  1. 洛谷P1523 旅行商简化版(DP)

    题目: P1523 旅行商简化版 解析 可以看做是两个人同时从西往东走,经过不一样的点,走到最东头的方案数 设\(f[i][j]\)表示一个人走到i,一个人走到j的最短距离(\(i<j\)) 第 ...

  2. [vijos P1014] 旅行商简化版

    昨天早上上课讲旅行商问题,有点难,这周抽空把3^n的算法码码看.不过这个简化版已经够折腾人了. 其一不看解析不知道这是双进程动态规划,不过我看的解析停留在f[i,j]表示第一个人走到i.第二个人走到j ...

  3. vijosP1014 旅行商简化版

    vijosP1014 旅行商简化版 链接:https://vijos.org/p/1014 [思路] 双线DP. 设ab,ab同时走.用d[i][j]表示ab所处结点i.j,且定义i>j,则有转 ...

  4. 洛谷【P1523】旅行商的背包(算法导论 15-1) 题解

    P1523 旅行商简化版 题目背景 欧几里德旅行商\((Euclidean Traveling Salesman)\)问题也就是货郎担问题一直是困扰全世界数学家.计算机学家的著名问题.现有的算法都没有 ...

  5. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

  6. 洛谷P1782 旅行商的背包[多重背包]

    题目描述 小S坚信任何问题都可以在多项式时间内解决,于是他准备亲自去当一回旅行商.在出发之前,他购进了一些物品.这些物品共有n种,第i种体积为Vi,价值为Wi,共有Di件.他的背包体积是C.怎样装才能 ...

  7. 2016全国研究生数学建模A题多无人机协同任务规划——基于分布式协同多旅行商MTSP遗传算法

    MTSP问题是指:有Ⅳ个城市,要求旅行商到达每个城市各一次,且仅一次,并[旦 1到起点,且要求旅行路线最短.而多旅行商问题M个旅行商从同一个城市(或多个城市)出发.分羽走一条旅路线,且总路程缀短.有关 ...

  8. Bzoj3352 [ioi2009]旅行商

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 89  Solved: 36 Description 旅行商认定如何优化旅行路线是一个非常棘手的计算问题 ...

  9. hdu 4281 Judges' response(多旅行商&DP)

    Judges' response Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

随机推荐

  1. 无法在要求对象展开的函数中使用 __try

    解决方案: 单独把try里面的代码封装成一个函数,然后再在try里面调用

  2. 框架-.NET:ASP.NET MVC

    ylbtech-框架-.NET:ASP.NET MVC ASP.NET MVC 是Windows系统下面的Web研发框架,有Microsoft提供.MVC顾名思义:Model, View, Contr ...

  3. web开发小知识

    session共享机制:f5刷新是再次提交之前的数据请求 地址栏回车属于不同的请求 不同浏览器获取不到之前数据 同一浏览器可以获取同步数据 session注销:session.invalidate() ...

  4. select change()

    $(".learnStageId").change(function(){ var id = $(this).val(); $(".gradeId").find ...

  5. Struts1.3——Struts入门

    1.Struts的几个基本概念 1.struts是一个开源框架(frameset) 2.struts是一个Web框架 3.struts是一个基于MVC的Web框架 2.为什么有struts 因为我们对 ...

  6. Spring JAR下载地址

    包含3.2版本及以上 http://repo.spring.io/libs-release-local/org/springframework/spring/ 包含从2.0开始的所有版本 http:/ ...

  7. 推荐MarkDown编辑工具Typora--文本画流程图示例

    程序员界名言:talk is cheap, show me the code CODE: ### 8. 修改预留手机号-per.MCReservedMobilePhoneUpd #### 8.1业务规 ...

  8. loj6626 幼儿园唱歌题

    题目 不难想到把\(S\)的反串\(S^R\)接到\(S\)后面,这样就可以把\(S[l_1,r_1]\)的前缀转化为\(S^R[n-r_1+1,n-l_1+1]\)的后缀 回文树上两节点的lca就是 ...

  9. Python之向函数传递元组和字典

    也可以在函数定义时加上这两个参数用以接收多余的参数哦~

  10. bootstrap学习(三)表单

    基本实例: from-group:可以是其内的标签排列更好 from-control:使标签宽度为100% <form> <div class="form-group&qu ...