算法學習:尺取法

昨天看了一下挑戰程序設計競賽,看到了尺取法,剛好博主最近寫到的一道題也可以使用尺取法。與原本的暴力求解對比,這種方法耗時爲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的循環中,不然會超時。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章