您的位置:首页 > 其它

uva1347(dp,双调欧几里得旅行商问题)

2018-03-18 15:12 429 查看
题意:给出n个点,确定一条连接各点的最短闭合旅程的问题。(将其转换成2个人同时从最左边出发,然后分别经过不同路径到达最右边的距离)

求解一般过程:

(1)首先将各点按照x坐标从小到大排列,时间复杂度为O(nlgn)。

(2)寻找子结构:定义d(i,j)为序号1~max(i,j)已经全部被访问过,并且当前位置在i和j。(规定i>=j,等于当且仅当在最左和最右时取到)同时,定义dis(i,j)为点Pi到Pj之间的直线距离。

(3)最优解:我们需要求的是d(1,1)。

注意:为了不遗漏情况,并方便理解,规定一次只能有一个人进行移动,且每次都会有一个人走到i+1这个位置,不管这个是走的快的那个人还是走的慢的那个人。假如是走的快的那个人走到了i+1这个位置,那就是由d(i,j)这个位置转移到了d(i+1,j)这个位置,以为后面位于j这个位置的人并没有移动,所以是d(i,j)。相反,如果这时是后面那个人(本来位置是j)移动到了i+1这个位置,那么本来位于i位置的人就不能移动了,那么就转变为了d(i+1,i)这个状态。

其余内容代码解释:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define eps 1e-8
#define pi 3.1415
typedef long long ll;
using namespace std;
int n;
struct node//结构体存储每个点的位置坐标
{
int x,y;
} e[1005];
double dp[1004][1004];//dp[i][j]表示两个人分别位于i和j位置时,还离目标的距离
double dis[1005][1005];
double solve(int i,int j)
{
if(dp[i][j]>0) return dp[i][j];//记忆化搜索
if(i==n)//需要一个跳出递归的条件
{
dp[i][j]=dis
[j];
return dp[i][j];
}
dp[i][j]=min(solve(i+1,j)+dis[i][i+1],solve(i+1,i)+dis[j][i+1]);//核心语句,
return dp[i][j];
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)scanf("%d%d",&e[i].x,&e[i].y);

memset(dp,-1,sizeof(dp));
dp

=0.0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
dis[i][j]=sqrt(pow(e[i].x-e[j].x,2.0)+pow(e[i].y-e[j].y,2.0));
}
}
printf("%.2lf\n",solve(1,1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: