尺取法:顾名思义,像尺子一样取一段,借用挑战书上面的话说,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的时候,所以说尺取法是一种高效的枚举区间的方法,是一种技巧,一般用于求取有一定限制的区间个数或最短的区间等等。当然任何技巧都存在其不足的地方,有些情况下尺取法不可行,无法得出正确答案,所以要先判断是否可以使用尺取法再进行计算。
本人为一名普通二本学校自动化专业的大二学生,对编程有着少许兴趣。
最近想了解什么是尺取法,于是想写道简单尺取法相关的题目,当练一练手。
最少连续页(poj3320)
题意:一本书有P页,每一页都一个知识点,求去最少的连续页数覆盖所有的知识点。
样例
输入:
6
1 1 3 1 2 3
输出:
3
备注:一本书有6页,第一页知识点为1…第6页知识点为3。
分析题意
按照尺取法的定义:一种高效的枚举区间的方法。我们应该先在找一个满足条件的区间(不一定是最优),然后再通过将左边界向右移、右边界向右移的方式需找最优区间。
第一步:找第一个满足条件区间
为了能够更好地找到最优区间,我们需要先了解有多少个不同的知识点、在已读的页数中每个知识点出现了几次。
map <int, int> cnt;
set <int> t;
//set主要是统计不同的知识点
//set不允许重复插入 每个元素都是不同的
//用map记录每个知识点在连续页中出现的次数
①:可以用set容器“不能重复插入”的特性,统计书中出一共有多少个不同的知识点。
for (int i = 0; i < p; i++)
{
scanf("%d", &a[i]);
t.insert(a[i]);
}
int num = t.size();
插入个数 num=3
②:可以用map容器“映射”的特性,统计出在已读的页数中相同知识点出现次数。
while (end<p && sum<num)
{
//选取不同知识点
if (cnt[a[end]] == 0)
sum++;
cnt[a[end]]++;
end++;
}