zoukankan      html  css  js  c++  java
  • poj 3258 River Hopscotch 二分答案

    题目地址: http://poj.org/problem?id=3258

    题目思路: 首先,如果只减少一部,那么一定要干掉最短的那段距离(一旦不消灭,最小的还是它,并没有达到使最小值取最大的理想情况)。 但是如果有很多边取到最小,具体去除哪一个点就有点麻烦了。如果两个最小距离连着,去除公共点最好。  如果没有连着,四个点分别考虑紧邻的,取最小的。 如果多于两条线段取最小随便去,如果仅有一条取最小仍是去紧邻较小的点。   很麻烦就是了。基于这样的思想,每次去掉一个顶点后,再取出最小边,同样处理(借助优先权队列)  。不知这样的贪心是不是对的...


    有一个二分答案的做法,现学的.

    一般的二分查找是

     while(left<=right)
       {
           mid=left+(right-left)/2;
           if(p[mid]==value)  return  mid;
    
           else if(p[mid]<value)
           {
               left=mid+1;
           }
           else right=mid-1;
       }
    

    这个是基于严格单调序列。


    看这个题。 首先理解映射关系,一个m对应了一个去m个点的方案集合,在这个集合中,每个方案都对应着执行以后,最短的线段是多少。  我们关心的是那些能取到最大可能值的方案。

    显然,m增大,这个对应的最大值f(m)  是在增大的。(在序列给定后,这个函数f是存在的)

    现在反过来,一个k,会有一个或者多个m值使f(m)=k,不确定是否存在反函数,但是对给定的k,最小的m0使f(m0)=k;却是唯一的,这样就找到了反函数h(k)=m;

    而且按照题意,“最小的最大” 保证了单调性 f(m+1)>=f(m); 

    下面来证明反函数性质(实际上很显然,这里啰嗦一下)

    设f(h(k))=x;

    h(k)使操作h(k) 次达到了k,x是最大可能值=> x>=k;

    按定义h(x) 是最小的,则h(x)<=h(k) 单调性=>  x<=k;

    x==k;

    那么我们只要设计一个函数求出h(k) 就行;

    如果扫描到一段比给定的最小值小,那么这里必须至少去一个点的,(见下面代码的min_move)可以证明,这个函数接近是h(k),只需要在真正求的时候增加一点优化就完美了


    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    using namespace std;
    
    int p[50005];
    
    int n;
    int min_move(int s)
    {
        int start=0;
    
        int ans=0;
        for(int i=1;i<=n+1;i++)
        {
            if(p[i]-p[start]<s)
            {
               ans++;
            }
            else start=i;
        }
    
      return ans;
    }
    int main()
    {
        int l,m;
        cin>>l>>n>>m;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&p[i+1]);
    
        }
        p[0]=0;
        p[n+1]=l;
    
        sort(p,p+n+1);   // 使在数轴上依次排列
    
        int left=0,right=l;
        int mid;
        int ans;
        while(left<=right)
        {
            mid=left+(right-left)/2;
    
             if(min_move(mid)<=m)
            {
               ans=mid;
               left=mid+1;
            }
            else right=mid-1;
        }
    
        cout<<ans<<endl;
    }
    
    最后注意不是一遇到min_move(mid) ==m 就break; 我们要找的是最大的长度,继续走下去逼近就行。




  • 相关阅读:
    GitHub 优秀的 Android 开源项目
    Android SDK代理服务器解决国内不能更新下载问题
    python拓展3 常用算法
    HTML+CSS实现页面
    数据库入门4 结构化查询语言SQL
    2016年蓝桥杯预选赛试题(水题)
    linux操作系统3 vi编辑器
    python应用之爬虫实战2 请求库与解析库
    python应用之爬虫实战1 爬虫基本原理
    SQL常用条件操作符
  • 原文地址:https://www.cnblogs.com/814jingqi/p/3339252.html
Copyright © 2011-2022 走看看