zoukankan      html  css  js  c++  java
  • 【状态压缩DP】NOIP2005-river过河

    【问题描述】

     在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧。在桥上有一些石子,青蛙很讨厌踩在这些石子上。由于桥的长度和青蛙一次跳过的距离都是正整数,我们可以把独木桥上青蛙可能到达的点看成数轴上的一串整点:0,1,……,L(其中L是桥的长度)。坐标为0的点表示桥的起点,坐标为L的点表示桥的终点。青蛙从桥的起点开始,不停的向终点方向跳跃。一次跳跃的距离是S到T之间的任意正整数(包括S,T)。当青蛙跳到或跳过坐标为L的点时,就算青蛙已经跳出了独木桥。

    题目给出独木桥的长度L,青蛙跳跃的距离范围S,T,桥上石子的位置。你的任务是确定青蛙要想过河,最少需要踩到的石子数。

    对于30%的数据,L <= 10000;

    对于全部的数据,L <= 10^9。

    【输入格式】

    输入的第一行有一个正整数L(1 <= L <= 10^9),表示独木桥的长度。第二行有三个正整数S,T,M,分别表示青蛙一次跳跃的最小距离,最大距离,及桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100。第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的起点和终点处没有石子)。所有相邻的整数之间用一个空格隔开。

    【输出格式】

    输出只包括一个整数,表示青蛙过河最少需要踩到的石子数。

    【思路】

    最最基础的DP+状态压缩。可以看出石头所在的点在整座桥上是非常稀疏的,所以对于长于s*t的点,都可以通过减去n*s*t得到对应的状态。为了方便起见,把第零块石头设为0,第m+1块石头设为l。

    【错因】

    犯下了两个错误。

    一个是状态压缩压过头了,至少要保留一个周期吧,一不小心连一个周期都没留,所以pos[i]-pos[i-1]>2*d,而不是d。

    另一个是因为第(m+1)块石头它其实是假想的,所以DP之前要把它归回到没有石头的行列。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 
     7 const int MAXN=200+5;
     8 const int MAXN2=10000+500;
     9 const int INF=0x7fffffff;
    10 
    11 int pos[MAXN];
    12 int l,s,t,m;
    13 int stone[MAXN2];
    14 
    15 void init()
    16 {
    17     scanf("%d",&l);
    18     scanf("%d%d%d",&s,&t,&m);
    19     for (int i=1;i<=m;i++)
    20         scanf("%d",&pos[i]);
    21     sort(pos+1,pos+m+1);
    22     pos[0]=0;
    23     pos[m+1]=l;
    24 }
    25 
    26 void easymode()
    27 {
    28     int ans=0;
    29     for (int i=1;i<=m;i++) if (pos[i]%s==0) ans++;
    30     cout<<ans<<endl;
    31 }
    32 
    33 void pretreat()
    34 {
    35     memset(stone,0,sizeof(stone));
    36     int d=s*t,nowd=0;
    37     for (int i=1;i<=m+1;i++)
    38     {
    39         pos[i]-=nowd;
    40         while (pos[i]-pos[i-1]>2*d) 
    41         /*这里是大于2*d而不是d,因为至少要保留一个最小公倍数*/ 
    42         {
    43             pos[i]-=d;
    44             nowd+=d;
    45         }
    46         stone[pos[i]]=1;
    47     }
    48     stone[pos[m+1]]=0;
    49     /*要把最终的位置重新回归到0*/
    50 }
    51 
    52 void dp()
    53 {
    54     int f[MAXN2];
    55     f[0]=0;
    56     int ans=INF;
    57     for (int i=1;i<=pos[m+1]+t-1;i++)
    58     {
    59         f[i]=INF;
    60         for (int j=s;j<=t;j++)
    61             if (i>=j) f[i]=min(f[i-j],f[i]);
    62             f[i]+=stone[i];
    63     }
    64     for (int i=pos[m+1];i<=pos[m+1]+t-1;i++)
    65         ans=min(ans,f[i]);
    66     cout<<ans<<endl;
    67 }
    68 
    69 int main()
    70 {
    71     freopen("river9.in","r",stdin);
    72     freopen("river9.out","w",stdout);
    73     init();
    74     if (s==t)
    75     {
    76         easymode();
    77     }
    78     else
    79     {
    80         pretreat();
    81         dp();
    82     }
    83     return 0;
    84 }
  • 相关阅读:
    PHP基本语法
    SQL-还原数据库,数据库提示正在还原中的处理办法
    MyBatis学习笔记
    Java byte数据转换和处理总结
    JS和JQUERY的区别
    .NET 之 ORM 性能评测
    你必须知道的 SmartSql !
    SmartSql 介绍
    SmartSql 入门
    SmartCode.ETL 这不是先有鸡还是蛋的问题!
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/4852826.html
Copyright © 2011-2022 走看看