hdoj 2224 && poj 2677 The shortest path 【TSP】

The shortest path

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1174    Accepted Submission(s): 597


Problem Description
There are n points on the plane, Pi(xi, yi)(1 <= i <= n), and xi < xj (i<j). You begin at P1 and visit all points then back to P1. But there is a constraint: 
Before you reach the rightmost point Pn, you can only visit the points those have the bigger x-coordinate value. For example, you are at Pi now, then you can only visit Pj(j > i). When you reach Pn, the rule is changed, from now on you can only visit the points those have the smaller x-coordinate value than the point you are in now, for example, you are at Pi now, then you can only visit Pj(j < i). And in the end you back to P1 and the tour is over.
You should visit all points in this tour and you can visit every point only once.
 

Input
The input consists of multiple test cases. Each case begins with a line containing a positive integer n(2 <= n <= 200), means the number of points. Then following n lines each containing two positive integers Pi(xi, yi), indicating the coordinate of the i-th point in the plane.
 

Output
For each test case, output one line containing the shortest path to visit all the points with the rule mentioned above.The answer should accurate up to 2 decimal places.
 

Sample Input
  
  
3 1 1 2 3 3 1
 

Sample Output
  
  
6.47 Hint: The way 1 - 3 - 2 - 1 makes the shortest path.
 

题意:给定二维平面上的n个点p[],要求从第一个点p[1]出发访问所有点有且仅有一次再返回p[1],且从左到右必须沿x坐标递增访问,从右到左必须沿x坐标递减访问。问你完成任务的最短路程。

估计题目忘说—— 一个x坐标只有一个点这个条件了。。。



思路:

把这个问题看做两个人A和B同时从p[1]走,分两条路线访问所有点(两个人重复访问的点只有第一个和最后一个)。

规定路线必须按照x坐标递增走。首先将所有点按x坐标升序排列。

设置dp[i][j]为A走到第i个点且B走到第j个点总路程,这里我们限制i < j(i != j)。  注意dp[i][j] = dp[j][i].

定义dis(i, j)表示i、j间距离。

一、i < j-1,由于A要在B的后面则j必须由B来走即:dp[i][j] = dp[i][j-1] + dis(j-1, j);

二、i == j-1,我们枚举到达j的前一个点k(1 <= k < j-1),这样有dp[i][j] = min(dp[j-1][k]+dis(k, j));这里dp[i][j]来源于状态——B到达第k个点且A到达第j-1个点,然后下一步B到达第j个点。

当然初始状态为dp[1][2] = dis(1, 2); 这样最后结果为dp[n-1][n] + dis(n, n);



AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <string>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define MAXN (200+10)
#define MAXM (200000+10)
#define Ri(a) scanf("%d", &a)
#define Rl(a) scanf("%lld", &a)
#define Rf(a) scanf("%lf", &a)
#define Rs(a) scanf("%s", a)
#define Pi(a) printf("%d\n", (a))
#define Pf(a) printf("%.2lf\n", (a))
#define Pl(a) printf("%lld\n", (a))
#define Ps(a) printf("%s\n", (a))
#define W(a) while(a--)
#define CLR(a, b) memset(a, (b), sizeof(a))
#define MOD 1000000007
#define LL long long
#define lson o<<1, l, mid
#define rson o<<1|1, mid+1, r
#define ll o<<1
#define rr o<<1|1
#define PI acos(-1.0)
using namespace std;
struct Node{
    int x, y;
};
Node num[MAXN];
bool cmp(Node a, Node b){
    return a.x < b.x;
}
double dis(int i, int j){
    return sqrt((num[i].x-num[j].x)*(num[i].x-num[j].x)*1.0 + (num[i].y-num[j].y)*(num[i].y-num[j].y));
}
double dp[MAXN][MAXN];
double dist[MAXN][MAXN];
int main()
{
    int n;
    while(Ri(n) != EOF)
    {
        for(int i = 1; i <= n; i++)
            Ri(num[i].x), Ri(num[i].y);
        sort(num+1, num+n+1, cmp);
        for(int i = 1; i <= n; i++)
            for(int j = i+1; j <= n; j++)
                dist[i][j] = dis(i, j);
        dp[1][2] = dist[1][2];
        for(int j = 3; j <= n; j++)
        {
            for(int i = 1; i < j-1; i++)
                dp[i][j] = dp[i][j-1] + dist[j-1][j];
            dp[j-1][j] = INF;
            for(int k = 1; k < j-1; k++)
                dp[j-1][j] = min(dp[j-1][j], dp[k][j-1] + dist[k][j]);
        }
        Pf(dp[n-1][n] + dist[n-1][n]);
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值