您的位置:首页 > 其它

尺取法

2015-08-10 14:52 253 查看
尺取法一般用来求解最大/最小区间问题。用两个指针代表区间的首尾,反复地推进区间的开头和末尾,来求取满足条件的最小/大区间,复杂度为O(n)。

当一个区间满足条件时,左指针推进,判断新区建是否满足条件,如果不满足条件,那么区间末尾向后扩展,直到满足条件为止。这样在区间推移过程中我们就得到了很多满足条件的区间,根据题意取最优即可。

当满足以下条件时,可以使用尺取法:若从

开始,至少要到

才能满足条件,即:最初满足条件的区间为

,则从

开始的最初满足条件的区间为

,必然有t≤t'。

例题: poj3061 Subsequence

设若从

开始总和最初不小于s时的连续子序列为

,这时

,所以从

开始总和最初大于s的连续子序列如果是

的话,则必然有t≤t'。所以可以用尺取法。

(1)以s = 0,t = 0,sum = 0初始化;

(2)只要依然有sum < S,就不断将sum累加

,并将t加1;

(3)如果(2)中无法满足sum >= S则终止,否则更新res = min(res, t - s + 1);

(4)将sum减去

,s增加1然后回到(2)。

由于t最多变化t次,故算法复杂度为O(n)。

代码如下:

#include <cstdio>
using namespace std;
#define N 100005
#define min(a, b) (a) < (b) ? (a) : (b)
int a
, sum
;

int main(){
int tc, n, s;
scanf("%d", &tc);
while(tc --){
scanf("%d %d", &n, &s);
sum[0] = 0;
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]), sum[i] = sum[i - 1] + a[i];
int beg = 1, en = 1, ans = N;
while(en <= n){
int tmp = sum[en] - sum[beg - 1];
if(tmp >= s)
ans = min(ans, en - beg + 1), ++beg;
else
++en;
}
printf("%d\n", ans == N ? 0 : ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: