3月2日 二分之《肖恩的苹果林》

文章描述了一个使用二分搜索解决编程问题的过程,目标是在数组x中找到满足条件的最大间隔值,使得至少选择m个间隔大于等于该值的点。通过循环和边界调整,最终输出确保选择m个元素的最大间隔值l。
摘要由CSDN通过智能技术生成
#include <iostream>
#include<algorithm>
using namespace std;
const int N=1e6+9;
int x[N];
int n,m;
int check(int mid)
{
  int res=0;
  for(int i=1,lst=0;i<=n;++i)
  {
    if(lst&&x[i]-x[lst]<mid)continue;
    res++,lst=i;
  }
  return res;
}
int main()
{
  cin>>n>>m;
  for(int i=1;i<=n;++i)cin>>x[i];
  sort(x+1,x+1+n);
  int l=0,r=1e9;
  while(l+1!=r)
  {
    int mid=(l+r)/2;
    if(check(mid)>=m)l=mid;
    else r=mid;
  }
  cout<<l<<endl;
  return 0;


  return 0;
}

在这个二分搜索算法中,我们要找到的是满足条件的最大间隔值,即在数组x中能选取元素的最大间隔值使得可以选择至少m个满足条件的点。这里我们使用了两个变量lr分别作为搜索区间的下限和上限。

关键点在于循环退出时,边界lr是相邻的整数,即�=�+1。在循环过程中:

  • 当发现某个间隔值mid使得可以选择出 >= m 个满足条件(间隔 >= mid)的点时,我们知道这个mid可能不是最大的可行解,但至少它是一个可行解,所以我们将下限提升到mid(l = mid)。
  • 如果这个间隔值mid无法保证选择出 >= m 个满足条件的点,则说明mid太大了,我们需要减小可接受的间隔。由于mid不可行,所以上限被压缩到了mid前面一个数(r = mid)。

当上下界相邻时�+1=�,此时循环结束:

  • l表示在确保可以选择出至少m个元素时当前已知的最大可行解。(因为如果更大会导致选不出足够的元素)
  • r表示第一个已知的不可行解。(因为比 r - 1 = l 大一位就已经选不出足够元素了)

由于要求最大可能的有效间隔,则距离应该取当前已知对于所寻找约束来说最右端(largest)且有效(feasible)的位置。此位置就是变量 l, 因此代码末端输出 l. 这样做基于如下逻辑:

最后check 函数返回值即是在给定间隔 mid 下按规则最多可以放置几棵数木。

  • 如果存在更宽松且仍然合理(更大临界但仍然有M或超过M个结果) 的情况,在向右查找过程 (增加L) 中一定早就遇到并已终止循环;
  • 否则 (附近没有更好答案),当前L是迄今为止找到并确保合理性 (至少M结果) 的边界,在给定信息下尽可能稀疏。
  • int check(int mid)
    {
      int res=0; // 初始化结果res,代表能够根据给定间距mid种植的树的数量
      for(int i=1,lst=0;i<=n;++i) // 开始遍历所有的位置,并使用变量lst记录上一次种树的位置。初始设为0(没有种过树)
      {
        if(lst&&x[i]-x[lst]<mid)continue; // 如果前一个点存在并且当前点与前一个种树点的距离小于mid,则跳过当前点。即:当前位置不能种树。
        res++; // 否则,在当前点种树,结果res加1
        lst=i; // 并且更新lst为当前点,也就是记录这个已经被用来种树的位置。
      }
      return res; // 遍历完所有位置后,返回总共能够种植的树木数量res。
    }
    

    这个 check 函数通过在所有可能的位置上模拟种植树木,来确定对于特定间隔 mid 是否可能至少种植下 m 株树。

    具体逻辑是:

  • 函数接受一个参数 mid 表示任意两棵相邻树之间至少需要保持的距离。
  • 它会一次考虑每一个可能放置一棵树的地方(包含n个)。
  • 对于每个可能放置一棵数的地方:
    • if 语句检查这个地方是否能放置一棵数(保证与上一棵种下的数至少有 mid 的距离)。
      • 如果不能,就继续检查下一个地方。
      • 如果可以,则将该地方作为新的上次放置数木之处,并增加计数器 res 来表示多了一棵符合条件の数木。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值