• Tour UVa 1347 (DAG)


    本题难在设置状态表示。

    题目要求先从左到右,再从右到左沿x轴方向经历坐标系上的点(1~n点),可以考虑成两条路径,分别从最左到最右,分别经历不同点且不能重合(除了起点和终点)。可以想到用$d(i,j)$表示一条路走到了$i$,一条路走到了$j$。因为两条路加起来要cover路径上所有点,所以$d(i,j)$可以表示$max(i,j)$和之前的点已经全被走过,还需走多远才能满足条件。因为两条路没有优劣,所以$d(i,j)==d(j,i)$,为了方便操作,可以规定要求$i>j$。可以用例子来理解:第一个人走到2,第二个人就只能停在1了,第一个人走到3,第一个人可以走到1或者2,第一个人走到4,第一个人可以走到1,2,3,始终让$i>j$可以满足结构的清晰。也就是说,$i$决定自己已经走到了最远的地方,而此时$j$停留在哪个地方,来保证$i$及以前的地方全部都被走过(可以理解为$j$给$i$擦屁股)。当$i$到达n时,$j$可以在路上$(1 ~ n-1)$中任何点,因为它走的是$i$走剩的点,所以$d(n,j)=0$。而状态方程可以写为:$d(i,j)=min[d(i+1,j)+dist(i,i+1),d(i+1,i)+dis(j,i+1)]$,其中$dist(a,b)$表示$a,b$之间的距离。

    边界条件:当$i$到达n时,$j$可以在路上$(1 ~ n-1)$中任何点,因为它走的是$i$走剩的点,所以$d(n,j)=0$。(这个边界条件是错误的,因为两条路径最终都要到最右端),我们可以理解$d(n,j)=dist(j,n)$,和上面的状态方程结合起来,可以得到$d(n-1,j)=dist(n-1,n)+dist(j,n)$(刘汝佳)(我觉得还是分开来看来处理边界条件比较方便)。起始的时候,因为规定了$i>j$,所以只能写$$d(2,1)$,然后加上1走到2的距离就是总距离了。

    代码如下:

     1 //
     2 //  main.cpp
     3 //  Tour
     4 //
     5 //  Created by Yanbin GONG on 12/3/2018.
     6 //  Copyright © 2018 Yanbin GONG. All rights reserved.
     7 //
     8 
     9 #include <iostream>
    10 #include <stdio.h>
    11 #include <string>
    12 #include <string.h>
    13 #include <algorithm>
    14 #include <cmath>
    15 
    16 using namespace std;
    17 
    18 struct coord{
    19     int x,y;
    20 };
    21 
    22 int n;//number of points
    23 coord nodes[105]; //假设最多100个点,UVa官网貌似没给大小
    24 double d[105][105];
    25 bool visited[105][105];
    26 double ans;
    27 
    28 
    29 double dis(int a, int b){
    30     return sqrt((nodes[a].x-nodes[b].x)*(nodes[a].x-nodes[b].x)+(nodes[a].y-nodes[b].y)*(nodes[a].y-nodes[b].y));
    31 }
    32 
    33 double dp(int a, int b){
    34     if(visited[a][b]==true){
    35         return d[a][b];
    36     }
    37     visited[a][b] = true;
    38     if(a==n){
    39         d[a][b] = dis(b,n);
    40         return d[a][b];//终点条件
    41     }
    42     d[a][b] = min(dp(a+1,b)+dis(a,a+1),dp(a+1,a)+dis(b,a+1));
    43     return d[a][b];
    44 }
    45 
    46 int main(){
    47     //原题用freopen,读取文件
    48     while(scanf("%d",&n)!=EOF){
    49         memset(d,0x3f,sizeof(d));
    50         memset(visited,0,sizeof(visited));
    51         for(int i=1;i<=n;i++){
    52             cin>>nodes[i].x>>nodes[i].y;
    53         }
    54         dp(2,1);
    55         ans = d[2][1] + dis(1,2);
    56         printf("%.2lf
    ",ans);
    57     }
    58     
    59     return 0;
    60 }
    View Code

     相同问题:OJ 440

  • 相关阅读:
    svn_linux + apache 实现网页访问svn
    SVN_2008R2 搭建流程与规范
    mysql 简称
    论运维之故障排查思路与方法
    mac pro 基本使用
    防火墙之netfailt、iptables详解
    翻转单词顺序列(剑指offer)
    中缀变为后缀
    左旋转字符串(剑指offer)
    和为S的两个数字(剑指offer)
  • 原文地址:https://www.cnblogs.com/cmbyn/p/8548651.html
Copyright © 2020-2023  润新知