MENU

高效的遍历之尺取法

April 4, 2020 • 算法

尺取法光靠语言解释起来可能有点复杂(当然他本身并不难,难的是我该如何更清楚的解释),所以我偷来了一张图

8uxYdK.gif

尺取法其实就是一种模拟,作为一种暴力算法的同时却不失优雅……

我们先引入一个例题:

NOJ P2124钻石收集者

Description

总是喜欢亮闪闪的东西的奶牛Bessie空闲时有挖掘钻石的爱好。她收集了N颗不同大小的钻石并且她希望将其中一些钻石放在谷仓展览室的一个盒子里。由于Bessie希望盒子里面的钻石在大小上相对接近,她不会将大小相差大于K的钻石放在盒子里。
现在给出K,请帮助Bessie计算她最多能选出多少颗钻石放在盒子里面。

Input

单组输入。
第一行2个正整数N和K,之间用一个空格隔开(1<=n<=1e6,0<=k<=1e5)
接下来的N行,每行包括1个正Si,表示第i颗钻石的大小(0<=Si<=1e5)

Output

一行一个整数,表示Bessie最多能选出多少颗钻石在盒子里面展览。

Sample Input

5 3
1 6 4 3 1

Sample Output

4

解析:

8uxYdK.gif

题目的意思是这只母牛想要取多个钻石,并且保证这些钻石的大小在一定范围K中,那这个题该怎么写呢?

很简单,我们可以利用尺取法!现在,想象有一条毛毛虫,他的嘴巴在指针R所指向的位置,屁股在指针L的位置,当他的嘴巴放在某个位置的时候,他就会吃掉这个位置上的食物(如果有的话),相反的,他的屁股却会在他离开这个位置的时候,将食物原封不动的吐出来(好恶心~~),好在这条虫子足够长,可以在肚子里放入一定的食物,而这个题目问的,便是这条虫子肚子里留下最多食物的数量

要求这个数量,我们就要先看看这条虫子有多长,题目要求我们,钻石的取值范围只能是K,所以虫子从头到尾巴,应当是K+1(尾巴不存东西,只管吐食物,好恶心~~)

按照这个原理,我们试着写写代码:

#include<bits/stdc++.h>
using namespace std;
map<int,int>s;
int main() {
    int number,range,item,max_size=0;
    cin>>number>>range;
    //range表示虫子的长度(不加尾巴),number表示钻石的总数
    while (number--){
        cin>>item;
        s[item]++;
        if (item>max_size) max_size=item;
        //记录最大数量,以确定虫子停下来的位置
    }
    int left=0,right=0,maxx=0;
    //定义虫子的嘴巴和尾巴,还有所吃食物的最大量maxx
    number=0;//number废变量重新使用,当虫子的肚子
    for (;right<=range;right++){
        if (s[right]){
            number+=s[right];
        }
    }
    //先让虫子伸直
    maxx=number;
    for (;right<max_size;left++,right++){
        if (s[left]){
            number-=s[left];
        }
        if (s[right]){
            number+=s[right];
            if (number>maxx) maxx=number;
        }
    }
    //开始吃和吐,并且记录最大值
    cout<<maxx;
    return 0;
}
作者:NorthCity1984
出处:https://grimoire.cn/algorithm/ruler.html
版权:本文《高效的遍历之尺取法》版权归作者所有
转载:欢迎转载,但未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任

Last Modified: April 10, 2020