UVA 1347_Tour

题意:

给定一系列按x坐标升序排列的点,一个人从左向右走到终点再从终点走回起点,要求每个点恰好经过一次,问所走过的最短路径长度。

分析:

可以看成是两个人同时从起点向终点走,且除起点终点外每个点恰有一个人经过。

John uses the following strategy: he starts from the leftmost point, then he goes strictly left to right to the rightmost point, and then he goes strictly right back to the starting point.

用d[i][j]表示一个人走到第i个位置,另一个人走到第j个位置时,已经共走了多少距离,规定其中i>j,且1~i全部走过。
题目要求严格按照从左到右和从右到左的顺序,所以不管哪个人下一步只能走i+1,i+2….如果一个人跳过i+1直接走到了i+2,则i+1必将由另一个人走,不妨让走i+1的人先走,这样便保证每次都先走到i+1,得到状态转移方程:(dist数组保存两点之间距离)

dp[i+1][j]=min(dp[i+1][j],dp[i][j]+dist[i+1][i]);
dp[i+1][i]=min(dp[i+1][i],dp[i][j]+dist[i+1][j]);

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=55, INF = 0x3fffffff; //为什么是55?
double x[maxn],y[maxn],dist[maxn][maxn],dp[maxn][maxn];
int main(void)
{
    int n;
    while(scanf("%d",&n) == 1){
        for(int i =0; i < n ; i++)
            scanf("%lf%lf",&x[i], &y[i]);
        for(int i = 0;i < n; i++)
            for(int j = 0 ; j < n ; j++)
              dist[i][j] = sqrt((x[i] - x[j]) * (x[i]-x[j]) + (y[i] - y[j]) * (y[i] - y[j]));

        for(int i = 0; i < n; i++){
            for(int j = 0; j < n; j++)
                dp[i][j] = INF;
        }
        dp[1][0]=dist[1][0];

        for(int i = 1; i < n - 1; i++) {
            for(int j = 0; j < i; j++){
                dp[i + 1][j] = min(dp[i + 1][j], dp[i][j] + dist[i + 1][i]);
                dp[i + 1][i] = min(dp[i + 1][i], dp[i][j] + dist[i + 1][j]);
            }
        }

       double ans = INF;
        for(int i = 0; i < n - 1; i++){
            ans = min(ans, dp[n-1][i] + dist[n - 1][i]);

        }
        printf("%.2lf
", ans);
    }
    return 0;
}

还可以用d[i][j]表示一个人走到第i个位置,另一个人走到第j个位置时,还剩多少距离,则状态转移方程

dp[i][j]=min(dist[i][i+1]+dp[i+1][j],dist[j][i+1]+dp[i+1][i]);  

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=55, INF = 0x3fffffff; //为什么是55?
double x[maxn],y[maxn],dist[maxn][maxn],dp[maxn][maxn];
int main(void)
{
    int n;
    while(scanf("%d",&n) == 1){
        for(int i =0; i < n ; i++)
            scanf("%lf%lf",&x[i],&y[i]);
        for(int i = 0;i < n; i++)
            for(int j = 0 ; j < n ; j++)
              dist[i][j] = sqrt((x[i] - x[j]) * (x[i]-x[j]) + (y[i] - y[j]) * (y[i] - y[j]));

        for(int i = n - 2; i >=1; i--) {
            for(int j = i - 1; j >= 0; j--){
                if(i == n - 2) dp[i][j] = dist[i][n - 1] + dist[j][n - 1];
                else
                    dp[i][j] = min(dist[i][i + 1]+dp[i + 1][j], dist[j][i + 1] + dp[i + 1][i]);
         }
    }
        printf("%.2lf
", dist[0][1] + dp[1][0]);
    }
    return 0;
}

貌似叫双调旅行商问题?

原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758847.html