zoukankan      html  css  js  c++  java
  • poj 3258 River Hopscotch 题解

    【题意】

    牛要到河对岸,在与河岸垂直的一条线上,河中有N块石头,给定河岸宽度L,以及每一块石头离牛所在河岸的距离,

    现在去掉M块石头,要求去掉M块石头后,剩下的石头之间以及石头与河岸的最小距离的最大值。

    【解法】

    用二分做,但是开始写了三个版本的二分,全都wa。

    无赖看了别人的二分,还是不理解,为什么他们写的就能过。

    反复思索后,终于明白了:关键在于题目求的是什么。

    做题思想:二分所求的最小距离的最大值mid,记录可以去掉的石头块数cnt(注意:当相邻的石头的距离小于等于mid,就可以去掉),

                      若cnt > M,h = h - 1 (这里是比较难理解的,也是我纠结挺久的地方),此时,应当回过头来看一下题目求的是什么:

                                                          寻找一个长度mid,使得可以去掉M块石头,剩下的石头中,石头间的最小距离为mid

                                                          但是cnt记录的是:相邻距离小于等于mid的块数,所以存在这样的一种情况  ---- cnt记录的所有石头中,

                                                          有很多块石头间的距离是等于mid,而距离小于mid的石头的块数是小于等于M的,此时,若将h的值减一,

                                                          那么h的值就变成一个小于题目所求的答案了。

                                                          举个例子就懂了:假设有9块石头,首尾的数都表示河岸。

                       石头的编号                      1     2     3     4     5        6         7     8      9  

                       石头到河岸的距离     0    4     5     7     9    12      16       19   23     26     28

                       相邻的距离                  4    1      2     2     3      4        3        3      3       2

                                                        假设l = 1,h = 5, M = 4    则mid = 3, 此时去掉的石头的编号为:2,3,5,7,9  cnt = 5

                                                        按照程序,h = h - 1 = 4,此时mid = 2,去掉的石头的编号就为:2,4,9     cnt = 3(cnt<M了,

                                                        当然也有可能cnt == M,总之就是cnt > M不成立了)

                                                        也就是说,之后求得的cnt <= M恒成立, 即题目的答案不在  l 和 h 之间了(这点

                                                       之前是让我很费解的地方),更准确地说,答案就是执行这次h-1之前的h值。

                      若cnt <= M,则l = l + 1,讨论一下:若cnt < M,明显当前的mid小了,l = l + 1;若cnt == M,则去掉cnt块石头后,

                                                       剩下的石头的最小值必然是大于mid的,所以进行操作l = l + 1。

                                                       然后解决上面遇到的问题,因为h已经小于答案了,而答案就是h+1,之后继续二分cnt <= M恒成立,

                                                       l 不断自增,直到跳出循环,因为答案为h+1,我们返回 l 的值,那么while的判断条件就是 l <= h,

                                                       当 l 自增到 h + 1时就跳出循环,l == h + 1,正好就是答案。

     写了这么多,就是分析了一下二分算法执行的过程,因为以前用的二分while判断条件都是 l < h,看样子以后做二分得多注意了,

    稍不注意就会有很多致命的小bug,一定要将对 l 和 h 的操作以及 while的判断条件结合起来考虑,要对二分算法进行灵活的变化,

    没有一成不变的模版,具体问题具体分析。

    【代码】

     1 /*
     2       Problem:poj 3258
     3       By:S.B.S.
     4 /*
     5 #include<iostream>
     6 #include<cstdio>
     7 #include<cstring>
     8 #include<cmath>
     9 #include<algorithm>
    10 #include<queue>
    11 #include<cstdlib>
    12 #include<iomanip>
    13 #include<cassert>
    14 #include<climits>
    15 #define maxn 10001
    16 #define F(i,j,k) for(int i=j;i<=k;i++)
    17 #define M(a,b) memset(a,b,sizeof(a))
    18 #define FF(i,j,k) for(int i=j;i>=k;i--)
    19 #define inf 0x7fffffff
    20 #define p 23333333333333333
    21 using namespace std;
    22 int l,n,m;
    23 int d[50005];
    24 int read(){
    25     int x=0,f=1;char ch=getchar();
    26     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    27     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    28     return x*f;
    29 }
    30 inline int run(int le,int h,int k)
    31 {
    32     int mid,last,cnt;
    33     while(le<=h)
    34     {
    35         mid=(le+h)>>1;
    36         last=cnt=0;
    37         F(i,1,n+1){
    38             if(mid>=d[i]-d[last]) cnt++;
    39             else last=i;
    40         }
    41         if(cnt>k) h=mid-1;
    42         else le=mid+1;
    43     }
    44     return le;
    45 }
    46 bool cmp(int a,int b)
    47 {
    48     return a<b;
    49 }
    50 int main()
    51 {
    52     std::ios::sync_with_stdio(false);//cout<<setiosflags(ios::fixed)<<setprecision(1)<<y;
    53 //  freopen("data.in","r",stdin);
    54 //  freopen("data.out","w",stdout);
    55     cin>>l>>n>>m;
    56     d[0]=0;
    57     d[n+1]=l;
    58     F(i,1,n){
    59         cin>>d[i];
    60     }
    61     sort(d+1,d+1+n,cmp);
    62     cout<<run(0,l,m)<<endl;
    63     return 0;
    64 }
    poj 3258
  • 相关阅读:
    ASCII对照表
    Python学习记录-3-简明Python教程-数据结构
    Python学习记录-2
    Python新手容易遇到的问题
    python学习问题之-编码
    同步与异步的概念(转自http://blog.chinaunix.net/uid-21411227-id-1826898.html)
    Objective-c学习三
    挺有意思的人体时钟代码(转自http://ziren.org/tools/hone-hone-clock.html)
    int ,long , long long类型的范围
    css3选择器使用例子
  • 原文地址:https://www.cnblogs.com/SBSOI/p/5639391.html
Copyright © 2011-2022 走看看