zoukankan      html  css  js  c++  java
  • Tour(dp)

    Tour(dp)

    给定平面上n(n<=1000)个点的坐标(按照x递增的顺序),各点x坐标不同,且均为正整数。请设计一条路线,从最左边的点出发,走到最右边的点后再返回,要求除了最左点和最右点之外每个点恰好经过一次,且路径总长度最短。两点间的长度为它们的欧几里得距离。

    首先转换一下题意,可以看作找到两条不相交(除了起点终点)且总长最短的路径。这种题型有一个套路,就是让两个点再路径上模拟前进。如果用(d(i, j))表示第一个人走到i,第二个人走到j,那么就不能设计出转移方程,因为不能保证两个人不会走到相同的点。没有定义好状态,导致转移困难。

    所以需要发现这道题的性质。走回头路肯定是不优的。因此,我们可以把状态修改为:(d(i, j))表示1~max(i, j)全部走过,且两个人的当前位置分别是i和j,走过的最短距离。不难由对称性发现(d(i, j)=d(j, i)),因此,在状态中规定i>j。状态转移的关系是:(d(i, j) to d(i+1, j) or d(i+1, i))。(本来是转移到i,i+1的,但是我们规定i>j)。至此状态转移方程就很明了了。这样的状态设计是包括所有可能正确的情况的。具体实现和边界处理参见代码。

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1005, INF=1e9;
    int n, x[maxn], y[maxn];
    double f[maxn][maxn], ans;
    
    inline int sqr(int x){ return x*x; }
    inline double dis(int a, int b){
        return hypot(x[a]-x[b], y[a]-y[b]);
    }
    
    int main(){
        while (~scanf("%d", &n)){
            for (int i=0; i<n; ++i)
                scanf("%d%d", &x[i], &y[i]);
            for (int i=0; i<n; ++i)
                for(int j=0; j<n; ++j) f[i][j]=INF;
            f[1][0]=0;
            ans=INF;
            for (int i=1; i<n; ++i){
                for (int j=0; j<i; ++j) if (i!=n-1){
                    f[i+1][j]=min(f[i+1][j], f[i][j]+dis(i, i+1));
                    f[i+1][i]=min(f[i+1][i], f[i][j]+dis(j, i+1));
                } else ans=min(ans, f[n-1][j]+dis(n-1, j));
            }
            printf("%.2lf
    ", ans+dis(0, 1));
        }
        return 0;
    }
    
  • 相关阅读:
    微信小程序开发常用方法
    HTML5 video常用属性
    移动端键盘定制
    移动端弹性滑动以及滑动出界解决方案
    vue移动端Ui组件 mint-ui 使用指南
    vue.js的ajax和jsonp请求
    获取用户地理位置
    如何将一个已有的项目托管到github或是码云上?git的配置
    mvvm模式和mvc模式 概述总结对比
    使用Java的BlockingQueue实现生产者-消费者
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/8857833.html
Copyright © 2011-2022 走看看