Traveling Salesman among Aerial Cities 旅行商(TSP)问题
题目链接:点我
问题:
给你n个点的坐标(x,y,z)。从点(a,b,c) 到另一个点 (p,q,r) 的距离是:|p−a|+|q−b|+max(0,r−c)
问你从一个点为起点,找一条能经过其他所有点的路径,最后回到起点(除了起点可以经过两次,其他所有点只能经过一次
问你这个环的长度最小是多少
问题求解:
假设从顶点s出发,令d(i, V)表示从顶点i出发经过V(是一个点的集合)中各个顶点一次且仅一次,最后回到出发点s的最短路径长度。
我们使用dist(i,j)表示从i点到j点的距离
1、当V是空集的时候,d(i,V)就表示直接从i点回到了s点,也就是dist(i,s)
2、当V不是空集的时候,那么就是对子问题的最优求解。你必须在V这个城市集合中,尝试每一个,并求出最优解。
d(i,V)=min(d(k,V-{k})+dist(i,k)) (V-{k}表示在V集合中把k点去掉
这也就是dp方程了
复杂度:
2n*n2
代码:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define min(a,b) ((a>b)?b:a)
using namespace std;
typedef long long ll;
const int maxn = 25 + 10;
const long long ll_INF=0x3f3f3f3f3f3f3f3fLL;
const long long INF=0x3f3f3f3f;
int n,w[maxn][maxn],dp[maxn][1<<20],m;
vector<int>path;
//dp[i][j]保存顶点i到状态j最后回到起始点的最小距离
struct Point
{
int x,y,z;
} point[maxn];
int dist(int i,int j)
{
return abs(point[i].x-point[j].x)+abs(point[i].y-point[j].y)+max(0,point[j].z-point[i].z);
}
void TSP()
{
//我们把起点看作0号节点
for(int i=0; i<n; ++i)
{
//初始化dp数组
dp[i][0]=w[i][0];
}
//按照dp方程求解
for(int j=1; j<m; ++j) //状态
{
for(int i=0; i<n; ++i)
{
dp[i][j]=INF;
if( ((j >> (i-1)) & 1) == 1) //这样判断而不是j>>i这样判断,是因为可以直接得到答案就在dp[n][m-1]
{
//要不然对于dp[n][m-1]的状态肯定每一位都是1,如果换成上面那个判断,那么这个状态的值就是
continue; //INF(因为continue掉了
}
for(int k=1; k<n; ++k)
{
if( ((j >> (k-1)) & 1) == 0)
{
continue;
}
if( dp[i][j] > w[i][k] + dp[k][j^(1<<(k-1))])
{
dp[i][j] = w[i][k] + dp[k][j^(1<<(k-1))];
}
}
}
}
}
//判断结点是否都以访问,不包括0号结点
bool isVisited(bool visited[])
{
for(int i = 1 ; i<n ; i++)
{
if(visited[i] == false)
{
return false;
}
}
return true;
}
//获取最优路径,保存在path中,根据动态规划公式反向找出最短路径结点
void getPath()
{
//标记访问数组
bool visited[n] = {false};
//前驱节点编号
int pioneer = 0,minn = INF, S = m - 1,temp ;
//把起点结点编号加入容器
path.push_back(0); while(!isVisited(visited))
{
for(int i=1; i<n; i++)
{
if(visited[i] == false && (S&(1<<(i-1))) != 0)
{
if(minn > w[i][pioneer] + dp[i][(S^(1<<(i-1)))])
{
minn = w[i][pioneer] + dp[i][(S^(1<<(i-1)))] ;
temp = i;
}
}
}
pioneer = temp;
path.push_back(pioneer);
visited[pioneer] = true;
S = S ^ (1<<(pioneer - 1));
minn = INF;
}
}
//输出路径
void printPath()
{
cout<<"最小路径为:";
vector<int>::iterator it = path.begin();
for(it ; it != path.end(); it++)
{
cout<<*it<<"--->";
}
//单独输出起点编号
cout<<0;
}
int main()
{
//printf("%d\n",(3>>(-1))); 6
scanf("%d",&n);
m=(1<<(n-1));
for(int i=0; i<n; ++i)
{
scanf("%d%d%d",&point[i].x,&point[i].y,&point[i].z);
}
for(int i=0; i<n; ++i)
{
for(int j=0; j<n; ++j)
{
if(i==j) w[i][j]=0;
else
w[i][j]=dist(i,j);
}
}
TSP();
printf("%d\n",dp[0][m-1]);
//下面用于输出路径
// getPath();
// printPath();
return 0;
}
Traveling Salesman among Aerial Cities 旅行商(TSP)问题的更多相关文章
- 遗传算法的简单应用-巡回旅行商(TSP)问题的求解
上篇我们用遗传算法求解了方程,其中用到的编码方式是二进制的编码,实现起来相对简单很多, 就连交配和变异等操作也是比较简单,但是对于TSP问题,就稍微复杂一点,需要有一定的策略, 才能较好的实现. 这次 ...
- 二进制状态压缩dp(旅行商TSP)POJ3311
http://poj.org/problem?id=3311 Hie with the Pie Time Limit: 2000MS Memory Limit: 65536K Total Subm ...
- Hamilton回路 旅行商TSP问题 /// dp oj1964
题目大意: 给出一个n个顶点的无向图,请寻找一条从顶点0出发,遍历其余顶点一次且仅一次.最后回到顶点0的回路——即Hamilton回路. Input 多测试用例.每个测试用例: 第一行,两个正整数 n ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- ACM/ICPC 之 数据结构-邻接表+DP+队列+拓扑排序(TSH OJ-旅行商TSP)
做这道题感觉异常激动,因为在下第一次接触拓扑排序啊= =,而且看了看解释,猛然发现此题可以用DP优化,然后一次A掉所有样例,整个人激动坏了,哇咔咔咔咔咔咔咔~ 咔咔~哎呀,笑岔了- -|| 旅行商(T ...
- 旅行商问题(Traveling Salesman Problem,TSP)的+Leapms线性规划模型及c++调用
知识点 旅行商问题的线性规划模型旅行商问题的+Leapms模型及CPLEX求解C++调用+Leapms 旅行商问题 旅行商问题是一个重要的NP-难问题.一个旅行商人目前在城市1,他必须对其余n-1个城 ...
- 【智能算法】用模拟退火(SA, Simulated Annealing)算法解决旅行商问题 (TSP, Traveling Salesman Problem)
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 文章声明 此文章部分资料和代码整合自网上,来源太多已经无法查明出处,如侵犯您的权利,请联系我删除. 01 什么是旅行商问题(TS ...
- 洛谷【P1523】旅行商的背包(算法导论 15-1) 题解
P1523 旅行商简化版 题目背景 欧几里德旅行商\((Euclidean Traveling Salesman)\)问题也就是货郎担问题一直是困扰全世界数学家.计算机学家的著名问题.现有的算法都没有 ...
- Speeding Up The Traveling Salesman Using Dynamic Programming
Copied From:https://medium.com/basecs/speeding-up-the-traveling-salesman-using-dynamic-programming-b ...
随机推荐
- 镜像批量迁移利器:image-transfer
概述 用户业务在上云或者云迁移过程中,需要对镜像进行批量迁移.基于此背景,腾讯云容器专家团队开发了镜像批量迁移工具:image-transfer.该工具支持多种云厂商镜像仓库之间的批量迁移,同时支持腾 ...
- LeetCode844 比较含退格的字符串
题目描述: 给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果. # 代表退格字符. 示例 1: 输入:S = "ab#c", T = ...
- 9. 细节见真章,Formatter注册中心的设计很讨巧
目录 本文提纲 版本约定 你好,我是A哥(YourBatman). Spring设计了org.springframework.format.Formatter格式化器接口抽象,对格式化器进行了大一统, ...
- RAC上的DG搭建
准备工作 修改rman_backup这个文件的所有者和所属组,修改为oracle用户的oinstall组的文件 #chown –R oracle:oinstall /rman_backup/ 主库和备 ...
- 【Oracle】regexp_substr()函数详解
环境:Oracle10.2.0.5 在SQL中尝试使用正则 可以试下regexp_substr()来进行分割 首先创建一个实验视图: SQL> create or replace view te ...
- 【Linux】linux中通过date命令获取昨天或明天时间的方法
date +"%F" 输出格式:2011-12-31 date +"%F %H:%M:%S" 输出格式:2011-12-31 16:29:50 这都是打印出系统 ...
- Python 身份证校验代码
Python 身份证校验代码 居民身份证bai编号识别 1.身份证编码规则如下:根据[中华人民共和国国家标准GB11643-1999]中有关公民身份号码的规定,公民身份号码是特征组合码,由十七位数字本 ...
- 封装JSONP 函数,方便请求发送
封装JSONP 函数,方便请求发送 封装jsonp的代码和封装Ajax的代码非常的相似!可以参照食用偶! <button id="btn">点击我发送请求!</b ...
- WinForm中实现按Enter将光标移动到下一个文本框
首先窗体加载出来是上面这个样子.有五个文本框,我们要实现的功能就是输入姓名后按Enter,使光标直接定位到手机号中. 在页面加载的时候我们就要获取所有文本框控件,并添加回车事件 private voi ...
- IDEA 简介
什么是IDEA IDEA 全称 IntelliJ IDEA,是 Java 语言开发的集成环境,IntelliJ 在业界被公认为最好的 Java 开发工具之一,尤其在智能代码助手.代码自动提示.重构.J ...