欧几里得旅行商问题 java与c++实现
双调欧几里得旅行商问题是一个经典动态规划问题。《算法导论(第二版)》思考题15-1
旅行商问题描述:平面上n个点,确定一条连接各点的最短闭合旅程。这个解的一般形式为NP的(在多项式时间内可以求出)
J.L. Bentley 建议通过只考虑双调旅程(bitonictour)来简化问题,这种旅程即为从最左点开始,严格地从左到右直至最右点,然后严格地从右到左直至出发点。下图(b)显示了同样的7个点的最短双调路线。在这种情况下,多项式的算法是可能的。事实上,存在确定的最优双调路线的O(n*n)时间的算法。
上图中,a是最短闭合路线,这个路线不是双调的。b是最短双调闭合路线
以上截取来自:http://blog.csdn.net/xiajun07061225/article/details/8092247
/**
* 欧几里得旅行商(travelling salesman problem)问题
* 分解模型:
* 一个人从Pi严格递减的走到P1,然后再严格递增的回到Pj,求总路径的最小值,其中P1,P2,...,Pj的
* 所有节点都要走一次,求最短的路径;
* 对于1 <= i <= j <= n, 我们定义P(i, j)是一条包含了P1, P2, P3 ...Pj的途径
* 这条路径可以分成2部分:递减序列与递增序列:起点是Pi(1 <= i <= j),拐点是P1,
* 终点是Pj, P[i, j]为其最小值;路径为(Pi-_>Pm-->P1-->Pn-->Pj,其中1<m<i<n<j)
* 动态规划方程:
* p[i,j]为最小值,dist(m,n)为m与n的直接距离
* p[1,2]=dist(1,2)
* i<j-1时,从P(i+1)到Pj之间的点必然出现在递增序列中
* p[i,j]=p[i,j-1]+dist(j-1,j)
* i=j-1时,假设P1到Pi之间的一个中间节点Pk,使得p[k,i]+dist(k,j)最小,也就是说,找到了
* 将P1到Pj的所有节点走一遍的最短路径
* p[i,j]=min{p[k,i]+dist(k,j)}(其中1<=k<=i)
* p[k,i]又可以按照以上方式继续找出最小路径
*
* 对于欧几里得旅行商问题,要求的最短路径是p[n,n]
* p[n,n]=p[n-1,n]+dist(n-1,n);
*
*
*/
</pre><pre name="code" class="html">
以下是C++实现,来自:http://blog.csdn.net/xiajun07061225/article/details/8092247
#include <iostream>
#include <cmath>
#include <iomanip> using namespace std; const int n = 7;//点的数目
const int MaxVal = 999999;
const int MaxLen = 201; struct tagPoint{
double x,y;
}; //计算点i和点j之间的直线距离
double distance(tagPoint *points,int i,int j)
{
return sqrt((points[i].x - points[j].x) * (points[i].x - points[j].x) +
(points[i].y - points[j].y) * (points[i].y - points[j].y));
} double DP(tagPoint *points,int n)
{
double b[MaxLen][MaxLen];//记录最短路径的长度
//计算所有情况下的b[i][j],1 <= i <= j
//初始化
b[1][2] = distance(points,1,2);
for (int j = 3;j <= n;++j)
{
//i < j-1
for (int i = 1;i <= j - 2;++i)
{
b[i][j] = b[i][j - 1] + distance(points,j - 1,j);
}
//i = j - 1,b[i][j] = min(b[k][j - 1] + distance(k,j));
b[j - 1][j] = MaxVal;
for (int k = 1;k <= j - 2;++k)
{
double temp = b[k][j - 1] + distance(points,k,j);
if (temp < b[j - 1][j])
{
b[j - 1][j] = temp;
}
}
} b[n][n] = b[n - 1][n] + distance(points,n - 1,n); return b[n][n];
} int main()
{
int NUM;
while(cin >> NUM)
{
tagPoint *points = new tagPoint[NUM + 1];
for (int i = 1;i <= NUM;++i)
{
cin >> points[i].x;
cin >> points[i].y;
}
double minDis = DP(points,NUM);
//设置输出格式:精确到小数点后2位
cout.setf(ios::fixed);
cout << setprecision(2) << minDis << endl;
}
}
以下是java实现,基本思想是一样的。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner; import org.omg.CORBA.PRIVATE_MEMBER; /**
* @date 2014-09-20
* @author acer
* 欧几里得旅行商(travelling salesman problem)问题
* 分解模型:
* 一个人从Pi严格递减的走到P1,然后再严格递增的回到Pj,求总路径的最小值,其中P1,P2,...,Pj的
* 所有节点都要走一次,求最短的路径;
* 对于1 <= i <= j <= n, 我们定义P(i, j)是一条包含了P1, P2, P3 ...Pj的途径
* 这条路径可以分成2部分:递减序列与递增序列:起点是Pi(1 <= i <= j),拐点是P1,
* 终点是Pj, P[i, j]为其最小值;路径为(Pi-_>Pm-->P1-->Pn-->Pj,其中1<m<i<n<j)
* 动态规划方程:
* p[i,j]为最小值,dist(m,n)为m与n的直接距离
* p[1,2]=dist(1,2)
* i<j-1时,从P(i+1)到Pj之间的点必然出现在递增序列中
* p[i,j]=p[i,j-1]+dist(j-1,j)
* i=j-1时,假设P1到Pi之间的一个中间节点Pk,使得p[k,i]+dist(k,j)最小,也就是说,找到了
* 将P1到Pj的所有节点走一遍的最短路径
* p[i,j]=min{p[k,i]+dist(k,j)}(其中1<=k<=i)
* p[k,i]又可以按照以上方式继续找出最小路径
*
* 对于欧几里得旅行商问题,要求的最短路径是p[n,n]
* p[n,n]=p[n-1,n]+dist(n-1,n);
* 解释:Pn-->Pn,如果第一个点是Pn-1,那么上面的式子显然成立;
* 如果第一个点是Pk,(1<=k<=n-2),那么Pn-1一定在Pk-->Pn的递增序列中,所以
* p[n,n]=p[k,n]+dist(k,n)=p[k,n-1]+dist(n-1,n)+dist(k,n);
* 其中p[n-1,n]=p[k,n-1]+dist(k,n)
* 所以 p[n,n]=p[n-1,n]+dist(n-1,n)必然成立;
*
*
*/
public class TSProblem { public static void main(String[] args) {
// TODO Auto-generated method stub
String line=null;//读取每一行的输入数据
int[][] pointXY;//记录横纵坐标 System.out.print("请输入点的个数N:");
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader bReader=new BufferedReader(isr);
try {
line=bReader.readLine().toString();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int n=Integer.parseInt(line);//记录点的个数
pointXY=new int[n][2]; System.out.println("请输入每个点的坐标,坐标格式为:x,y (以EOF结束输入)");
Scanner scn=new Scanner(System.in);
int i=0;
while(!"EOF".equals(line=scn.nextLine())){
String[] p=line.split(",");
int j=0;
for(String str:p){
pointXY[i][j++]=Integer.parseInt(str);
}
i++;
if(i>=n){
System.out.println("输入的点数已经足够,自动结束输入");
break;//退出输入
} } //System.out.println("ok");
int length=pointXY.length;
TSProblem tsp=new TSProblem(pointXY,length); } public TSProblem(int[][] points,int length){
//points中存储所有的节点,乱序排列
//1、首先将所有的节点按照x坐标顺序排列,可选用多种排序方式,这里采用快排,时间复杂度为o(nlogn)
points=this.QuickSort(points, 0, length-1);
// //打印排序后的点
// for(int i=0;i<length;i++){
// System.out.println(points[i][0]+","+points[i][1]);
// } //2、找到最短路径
double leastDis=DP(points, length); System.out.println("最短路径为:"+leastDis); } //计算最短旅行路径
double DP(int[][] points,int length){ //p用于记录最短路径的长度
double[][] p=new double[length][length];
p[0][1]=dist(points, 0, 1);
for(int j=2;j<length;j++){
//case1:i<j-1
// p[i,j]=p[i,j-1]+dist(j-1,j)
for(int i=0;i<j-1;i++){
p[i][j]=p[i][j-1]+dist(points, i, j);
} //case2:i=j-1
// p[i,j]=min{p[k,i]+dist(k,j)}(其中1<=k<=i)
p[j-1][j]=Float.MAX_VALUE;
double temp=0;
for(int k=0;k<j-1;k++){
temp=p[k][j-1]+dist(points, k, j);
if(temp<p[j-1][j]){
p[j-1][j]=temp;
}
} }
p[length-1][length-1]=p[length-2][length-1]+dist(points, length-2, length-1); //返回Pn-->Pn,即最短路径
return p[length-1][length-1]; } //计算两点之间的直接距离dist(i,j)
double dist(int[][] point ,int i,int j){
double distance=0;
distance=Math.sqrt(Math.pow((point[j][0] -point[i][0]),2)
+Math.pow((point[j][1]-point[i][1]),2)); return distance;
} //快排
int[][] QuickSort(int[][] num,int left,int right){
/**
* 1、先从数列中取出一个数作为基数
* 2、大数置于该数的右边,小数置于该数的左边
* 3、重复步骤1,2
*/
if(left<right){
int tempX=num[left][0];//设置基数,不唯一
int tempY=num[left][1];
int i=left,j=right;
while(i<j){
while(i<j&&num[j][0]>=tempX)
j--; //右边的数小于基数时退出
if(i<j){
//如果在右边找到一个数小于基数,num[i]此时为空,将该数填到num[i]
num[i][0]=num[j][0];
num[i][1]=num[j][1];
i++;
}
while(i<j&&num[i][0]<tempX)
i++; //左边的数大于基数时退出
if(i<j){
//如果在左边找到一个数大于基数,num[j]此时为空,将该数填到num[j]
num[j][0]=num[i][0];
num[j][1]=num[j][1];
j--;
} }//当i=j时退出
//num[i]为空值,将基数填入
num[i][0]=tempX;
num[i][1]=tempY; QuickSort(num, left, i-1);//左边快排
QuickSort(num, i+1, right);//右边快排 }
//返回已经排好序的数组
return num;
} }
欧几里得旅行商问题 java与c++实现的更多相关文章
- 2014百度之星第二题Disk Schedule(双调欧几里得旅行商问题+DP)
Disk Schedule Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...
- POJ2677 Tour(DP+双调欧几里得旅行商问题)
Tour Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3929 Accepted: 1761 Description ...
- 2014年百度之星程序设计大赛 - 资格赛 1002 Disk Schedule(双调欧几里得旅行商问题)
Problem Description 有非常多从磁盘读取数据的需求,包含顺序读取.随机读取.为了提高效率,须要人为安排磁盘读取.然而,在现实中,这样的做法非常复杂.我们考虑一个相对简单的场景.磁盘有 ...
- 双调欧几里得旅行商问题(TSPhdu2224)
http://acm.hdu.edu.cn/showproblem.php?pid=2224 The shortest path Time Limit: 1000/1000 MS (Java/Othe ...
- hdu 2224 双调欧几里得旅行商问题tsp
/* 题意:平面上n个点,确定一条连接各点的最短闭合旅程且每个点仅用一次.这个解的一般形式为NP的(在多项式时间内可以求出) 建议通过只考虑双调旅程(bitonictour)来简化问题,这种旅程即为从 ...
- hdu_1576A/B(扩展欧几里得求逆元)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1576 A/B Time Limit: 1000/1000 MS (Java/Others) Me ...
- Root(hdu5777+扩展欧几里得+原根)2015 Multi-University Training Contest 7
Root Time Limit: 30000/15000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total Su ...
- hdu2669-Romantic-(扩展欧几里得定理)
Romantic Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- HDU1576(扩展欧几里得)
A/B Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
随机推荐
- UITableViewCell的选中时的颜色及tableViewCell的selecte与deselecte
1.系统默认的颜色设置 //无色 cell.selectionStyle = UITableViewCellSelectionStyleNone; //蓝色 cell.selectionStyle = ...
- hibernate简单应用
Hibernate 第二章 核心API 和CURD实现 核心API介绍 单表操作方法 查询hql语句 1.认识hibernate 核心思想ORM:实现数据库中的文件一一映射为java中的实体类. 使用 ...
- nyoj 32 组合数
组合数 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 找出从自然数1.2.... .n(0<n<10)中任取r(0<r< ...
- 在HTML中怎么去掉a标签(超链接)的下划线?
<style type="text/css">a:link,a:visited{ text-decoration:none; /*超链接无下划线*/}a:hover{ ...
- 如何搭建javaweb 开发环境
一.准备工作: (1) 环境要求: 1.java jdk 2.eclipse--j2ee版 3.tomcat 4.mysql 5.HeidiSQL_7.0 (2)搭建步骤: 1.安装JDK,配置环境变 ...
- 20151207jquery 学习笔记 Ajax
.load()方法是局部方法,因为他需要一个包含元素的 jQuery 对象作为前缀.而$.get()和 $.post()是全局方法,无须指定某个元素.对于用途而言,.load()适合做静态文件的异步获 ...
- 产品原型设计5:移动App原型设计神器 - POP(Prototyping on Paper)
一般来说,苦逼的互联网产品经理们都知道 Axure 这个原型设计工具,一方面是因为它提供了足够简单的拖拽操作,易上手,且有很多模板方便复用:另一方是因为它可直接输出html,直接在浏览器里给团队成员和 ...
- ios Objective-C的动态特性
这是一篇译文,原文在此,上一篇文章就是受这篇文章启发,这次干脆都翻译过来. 过去的几年中涌现了大量的Objective-C开发者.有些是从动态语言转过来的,比如Ruby或Python,有些是从强类型语 ...
- 四、使用Maven和使用Eclipse构建javaWeb项目
环境前边已经搭建过了,我们就再弄了. 1.使用Maven构建javaWeb项目 (1).键入以下命令: $ mvn archetype:generate -DgroupId=com.holytax.w ...
- swift-06-字符串,字符以及元组类型
1.字符串和字符类型 //在swift中,字符串使用一对双引号括起来 var str = "hello M.SD-DJ" print(str) //字符也要用双引号括起来,用cha ...