zoukankan      html  css  js  c++  java
  • 3510. 【NOIP2013模拟11.5B组】最短路径(path)

    Description

    平面内给出 n 个点,记横坐标最小的点为 A,最大的点为 B,现在Zxd想要知道在每个点经过一次(A 点两次)的情况下从 A 走到 B,再回到 A 的最短路径。但他是个强迫症患者,他有许多奇奇怪怪的要求与限制条件:
    1.  从 A 走到 B 时,只能由横坐标小的点走到大的点。
    2.  由 B 回到 A 时,只能由横坐标大的点走到小的点。
    3.  有两个特殊点 b1 和 b2, b1 在 0 到 n-1 的路上,b2 在 n-1 到 0 的路上。
    请你帮他解决这个问题助他治疗吧!
     

    Input

    第一行三个整数 n,b1,b2,( 0 < b1,b2 < n-1 且 b1 <> b2)。n 表示点数,从 0 到 n-1 编号,b1 和 b2 为两个特殊点的编号。
    以下 n 行,每行两个整数 x、y 表示该点的坐标(0 <= x,y <= 2000),从 0 号点顺序
    给出。Doctor Gao为了方便他的治疗,保证所有点横坐标不同,并且已经将给出的点按 x 增序排好了。
     

    Output

    仅一行,输出最短路径长度(精确到小数点后面 2 位)
     
    Solutions

    考虑到每个点只能走一次,且从终点往回走和从起点再走一遍到终点没有区别,所以这道题可以转化为求两条不相交路径和的最小值。

        于是考虑用动态规划求解。

        用F[i][j]表示第一个点走到i,第二个点(回去的那个点)走到j的最优值。

        为了保证更新时不会更新出F[i][i](即一个点走了两次),而且每个点都会在路径上,我们每次用F[i][j]去更新点max(i,j)+1,所以转移方程为:

        F[0][0]=0; k=max(i,j)+1,

        F[k][j]=max(F[k][j],F[i][j]+Dis(i,k));

        F[i][k]=max(F[i][k],F[i][j]+Dis(j,k));

        Dis(i,j)为从i直接走到j点的距离.

    对于两个特殊点和max(i,j)=N的情况特判处理即可。

    期望得分:100(本代码为此做法)

        同时上面的DP也可以用记忆化搜索实现,对于abs(x-y)>1的情况,说明当前情况只能从max(x,y)-1转移过来,当abs(x-y)=1时,则能从1~min(x,y)中的任意一点转移过来,于是用记忆化搜索完成上面的步骤,加上适当剪枝即可。

    期望得分:60~100分

    代码

     1 var
     2   n,b1,b2:longint;
     3   x,y:array [0..1001] of longint;
     4   f,b:array [0..1001,0..1001] of real;
     5 procedure init;
     6 var
     7   i:longint;
     8 begin
     9   readln(n,b1,b2);
    10   b1:=b1+1; b2:=b2+1;
    11   for i:=1 to n do
    12     readln(x[i],y[i]);
    13 end;
    14 
    15 function min(o,p:real):real;
    16 begin
    17   if o<p then exit(o);
    18   exit(p);
    19 end;
    20 
    21 function max(o,p:longint):longint;
    22 begin
    23   if o>p then exit(o);
    24   exit(p);
    25 end;
    26 
    27 procedure main;
    28 var
    29   i,j,k:longint;
    30 begin
    31   for i:=1 to n-1 do
    32     for j:=i+1 to n do
    33       begin
    34         b[i,j]:=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
    35         b[j,i]:=b[j,i];
    36       end;
    37   for i:=0 to n do
    38     for j:=0 to n do
    39       f[i,j]:=maxlongint div 3;
    40   f[1,1]:=0;
    41   for i:=1 to n do
    42     for j:=1 to n do
    43       if (i<>j) or (i=1) then
    44         begin
    45           k:=max(i,j)+1;
    46           if k=n+1 then
    47             begin
    48               if i<>n then f[n,n]:=min(f[n,n],f[i,j]+b[i,n]);
    49               if j<>n then f[n,n]:=min(f[n,n],f[i,j]+b[j,n]);
    50               continue;
    51             end;
    52           if k<>b1 then f[i,k]:=min(f[i,k],f[i,j]+b[j,k]);
    53           if k<>b2 then f[k,j]:=min(f[k,j],f[i,j]+b[i,k]);
    54         end;
    55   writeln(f[n,n]:0:2);
    56 end;
    57 
    58 begin
    59   init;
    60   main;
    61 end.
  • 相关阅读:
    CSS浏览器兼容性问题集()两
    HTML5 Introduction
    poj 2449 Remmarguts&#39; Date 【SPFA+Astar】【古典】
    LwIP学习笔记——STM32 ENC28J60移植与入门
    在四川大学的第二个冠军游戏在线编程:Peter的X
    ArcEngine下一个TIN生成的轮廓
    精彩理发头盔
    UBUNTU如何改变mysql默认文件夹数据文件夹
    第一章 词汇陷阱
    LINUX2.4.x网络安全框架
  • 原文地址:https://www.cnblogs.com/zyx-crying/p/9329487.html
Copyright © 2011-2022 走看看