zoukankan      html  css  js  c++  java
  • POJ1661

    题目链接:http://poj.org/problem?id=1661

    解题思路:

      离散化处理 + DP。

      首先,纵坐标除了用来判断老鼠是否会摔死之外基本没用,主要考虑横坐标,只要求出在横坐标上必须走的最短距离,加上题目给出的Y就是答案了。由题目知-20000 <= X, X1[i], X2[i] <= 20000,为了方便后面的处理,我们把这三个数据统一加上20000,不让他出现负数。

      接下来介绍DP的思路,dp[i][x]——代表走到第 i 个平台的横坐标为 x 的点所需走过的最短距离(这里的距离其实都只是考虑横坐标上的距离,不考虑纵坐标,下面的讨论也一样),但是 1 <= N <= 1000 和 x 数据范围显然不允许我们开出这么大的数组,因此我们可以用离散化的技巧,把 x 的数据范围缩小为 [0,2000],这样就勉强可以开出数组了。我们先把平台按照高度由高到低的顺序排好序,则 dp[i][x] = min(dp[i][x] , dp[j][第 j 个平台的左端点坐标](条件:老鼠从第  j 个平台掉到第 i 个平台不会掉死并且这两点之间没有其他平台,右端点一样), dp[j][第 j 个平台的右端点坐标])(j 是从老鼠掉下来的第一个平板到第 i 个平板之间的所有平板)。

      具体细节请看代码。

    AC代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 using namespace std;
     6 const int maxn=1000+5,inf=0x7ffffff;
     7 struct node{
     8     int x1,x2,h;
     9 }plat[maxn];
    10 bool cmp(node &a, node &b){
    11     return a.h>b.h;
    12 }
    13 int dp[maxn][maxn<<1];
    14 int xs[maxn<<1],x_on[40004];
    15 int vis[maxn][2];   //0,左端点;1,右端点。这个vis数组是重点,标记第i个平台的左右端点是否已经处理过了
    16 int main(){
    17     int t,X,Y,N,MAX;
    18     scanf("%d",&t);
    19     while(t--){
    20         memset(vis,0,sizeof(vis));
    21         memset(x_on,-1,sizeof(x_on));
    22         scanf("%d%d%d%d",&N,&X,&Y,&MAX);
    23         X+=20000;               //记得X也要加20000
    24         int x_num=0;
    25         for(int i=0;i<N;i++){
    26             scanf("%d%d%d",&plat[i].x1,&plat[i].x2,&plat[i].h);
    27             plat[i].x1+=20000, plat[i].x2+=20000;
    28             
    29 //离散化
    30 //*******************************************************************
    31             if(x_on[plat[i].x1]==-1){
    32                 x_on[plat[i].x1]=x_num; xs[x_num++]=plat[i].x1;
    33             }
    34             if(x_on[plat[i].x2]==-1){
    35                 x_on[plat[i].x2]=x_num;    xs[x_num++]=plat[i].x2;
    36             }
    37         }
    38         sort(xs,xs+x_num);
    39         for(int i=0;i<x_num;i++)
    40             x_on[xs[i]]=i;
    41 //********************************************************************
    42 
    43         int newx;
    44         sort(plat,plat+N,cmp);
    45         
    46         int start;
    47         for(start=0;start<N;start++){
    48             if(plat[start].x1<=X&&plat[start].x2>=X)
    49                 break;
    50             vis[start][0]=vis[start][1]=1;
    51         } //找出老鼠落下的第一个平台,上面的平台不会再用到了,我们随手处理一下访问标记
    52         
    53         if(start==N){       //老鼠直接掉到地上的情况也不能忘了考虑哦
    54             printf("%d
    ",Y);
    55             continue;
    56         }
    57         
    58         for(int i=0;i<N;i++){
    59             for(int j=0;j<x_num;j++)    dp[i][j]=inf;
    60         }
    61         newx=x_on[plat[start].x1];
    62         dp[start][newx]=X-plat[start].x1;
    63         newx=x_on[plat[start].x2];
    64         dp[start][newx]=plat[start].x2-X;
    65         for(int i=start+1;i<N;i++){
    66             int l=plat[i].x1,r=plat[i].x2,h=plat[i].h;
    67             for(int j=start;j<i;j++){
    68 //如果第j个平台的端点已经被访问了,即对应的vis数组为1,就说明在这个端点到第i个平台之间有平台阻挡
    69                 if(vis[j][0]&&vis[j][1])  continue;  
    70                 if(plat[j].h-h>MAX)     continue;
    71                 
    72                 if(!vis[j][0]&&plat[j].x1<=r&&plat[j].x1>=l){
    73                     vis[j][0]=1;
    74                     dp[i][x_on[l]]=min(dp[i][x_on[l]],dp[j][x_on[plat[j].x1]]+plat[j].x1-l);
    75                     dp[i][x_on[r]]=min(dp[i][x_on[r]],dp[j][x_on[plat[j].x1]]+r-plat[j].x1);
    76                 }
    77                 if(!vis[j][1]&&plat[j].x2<=r&&plat[j].x2>=l){
    78                     vis[j][1]=1;
    79                     dp[i][x_on[l]]=min(dp[i][x_on[l]],dp[j][x_on[plat[j].x2]]+plat[j].x2-l);
    80                     dp[i][x_on[r]]=min(dp[i][x_on[r]],dp[j][x_on[plat[j].x2]]+r-plat[j].x2);
    81                 }
    82             }
    83         }
    84         int ans=inf;
    85         for(int i=N-1;i>=start;i--){
    86 //从最后一个平台往前遍历,凡是vis标记为0的,即证明这一点没有被处理过,也就证明这一点到地面之间没有阻挡,那么可以从这一点直接跳到地面
    87             if(plat[i].h>MAX)   break;     //遍历到高度大于MAX的平台就结束
    88             if(!vis[i][0])
    89                 ans=min(ans,dp[i][x_on[plat[i].x1]]);
    90             if(!vis[i][1])
    91                 ans=min(ans,dp[i][x_on[plat[i].x2]]);
    92         }
    93         printf("%d
    ",ans+Y);
    94     }
    95     return 0;
    96 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    activity 背景透明
    win系统注册缺少的库 32位系统 64位系统
    android 窗
    wireshark抓包分析
    juqery select 标签
    IOS开发应用之Quartz 2D学习指南
    为什么你总会觉得自己的产品不够好
    日志宝
    Android之Inflate()方法用途+setContentView和inflate区别
    Ralasafe
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/7294181.html
Copyright © 2011-2022 走看看