昨天看了一下挑战程序设计竞赛,看到了尺取法,刚好博主最近写到的一道题也可以使用尺取法。与原本的暴力求解对比,这种方法耗时为O(n)。有些想法,现在写出来加深印象,有不足之处望大牛们指正。
尺取法指对一个数组保存一对下标(起点和终点),依照需要交替移动两下标,按此扫描数组,直到找到答案。能够在线性时间内解决一类问题。这样对一个数组上的求解问题可以从一般的O(n^2)降低为O(n)。
POJ3061 Subsequence
Description
A sequence of N positive integers (10< N < 100 000), each of them less than or equal 10000, and a positiveinteger S (S < 100 000 000) are given. Write a program to find the minimallength of the subsequence of consecutive elements of the sequence, the sum ofwhich is greater than or equal to S.
Input
The first line is the number of testcases. For each test case the program has to read the numbers N and S,separated by an interval, from the first line. The numbers of the sequence aregiven in the second line of the test case, separated by intervals. The inputwill finish with the end of file.
Output
For each the case the program has toprint the result on separate line of the output file.if no answer, print 0.
求出数组中连续数字和大于s的最短序列长度。这道题就可以使用尺取法解决,记录左端下标left和右端下标right。记当前所有数的和为sum,当sum<s的时候向前移动right并加上当前数,直到sum>s此时right-left即为满足要求的一个序列的长度。然后将left向前移动,并减去原本left位置的数字,然后继续循环,直到所有数都被考察。最后输出最小的ans。
#include<iostream>
#define INF 100005
using namespace std;
int l,r,sum;
int ans,a[100005];
int main()
{
ios::sync_with_stdio(false);
int T;
cin>>T;
while (T--)
{
int n,s;
sum=0;
r=l=0;
ans=INF;
cin>>n>>s;
for (int i=0;i<n;i++)
{
cin>>a[i];
}
while (1)
{
while (sum<s&&r<n)
{
sum+=a[r++];
}
if (sum<s)
break;
ans=min(ans,r-l);
sum-=a[l++];
}
if (ans>n)
cout<<"0\n";
else
cout<<ans<<"\n";
}
return 0;
}
POJ3320Jessica's Reading Problem
Description
Jessica's a verylovely girl wooed by lots of boys. Recently she has a problem. The final examis coming, yet she has spent little time on it. If she wants to pass it, shehas to master all ideas included in a very thick text book. The author of thattext book, like other authors, is extremely fussy about the ideas, thus someideas are covered more than once. Jessica think if she managed to read eachidea at least once, she can pass the exam. She decides to read only onecontiguous part of the book which contains all ideas covered by the entirebook. And of course, the sub-book should be as thin as possible.
A very hard-workingboy had manually indexed for her each page of Jessica's text-book with whatidea each page is about and thus made a big progress for his courtship. Hereyou come in to save your skin: given the index, help Jessica decide whichcontiguous part she should read. For convenience, each idea has been coded withan ID, which is a non-negative integer.
Input
The first line ofinput is an integer P (1 ≤ P ≤ 1000000), which is the number ofpages of Jessica's text-book. The second line contains P non-negative integers describing whatidea each page is about. The first integer is what the first page is about, thesecond integer is what the second page is about, and so on. You may assume allintegers that appear can fit well in the signed 32-bit integer type.
Output
Output one line: thenumber of pages of the shortest contiguous part of the book which contains allideals covered in the book.
一本书有p页,其中有若干知识点,求看完所有知识点最少需要看书多少页。
同样是可以使用尺取法的,但是一开始没有给出知识点的个数需要事先求出来。这里可以使用STL中的set。(STL的妙用有很多,现在还有很多都没有接触过)。
#include<iostream>
#include<set>
#include<map>
using namespace std;
int a[1000005];
set<int> tmp;
int main()
{
ios::sync_with_stdio(false);
int p;
while (cin>>p)
{
tmp.clear();
for (int i=0;i<p;i++)
{
cin>>a[i];
}
for (int i=0;i<p;i++)
tmp.insert(a[i]);
int n=tmp.size();
map<int,int> k;
int l=0,r=0,sum=0;
int ans=p;
while(1)
{
while (sum<n&&r<p)
{
if (k[a[r++]]++==0)
{
sum++;
}
}
if (sum<n)
break;
if (ans>r-l)
ans=r-l;
if (--k[a[l++]]==0)
{
sum--;
}
}
cout<<ans<<endl;
}
return 0;
}
对所有知识点个数求解部分使用set实现,但是这个部分不能放到输入数组a的循环中,不然会超时。