尺取法還是蚯蚓法

尺取法,顧名思義,像尺子一樣,一塊一塊的截取。

是不是感覺從字面很難理解?

我們直接看例題:poj-3061
題目翻譯:

給定長度爲N的數列整數a0,a1,a2,a3 ….. an-1以及整數S。求出綜合不小於S的連續子序列的長度的最小值。如果解不存在,則輸出0。

限制條件:
10< N<10^5, S<10^8, a[]<1000

這裏我們拿第一組測試數據舉例子,即

n=10, S = 15, a = {5,1,3,5,10,7,4,9,2,8}
這裏寫圖片描述
這幅圖便是尺取法怎麼“取”的過程了。

整個過程分爲4步:
  1.初始化左右端點
  2.不斷擴大右端點,直到滿足條件
  3.如果第二步中無法滿足條件,則終止,否則更新結果
  4.將左端點擴大1,然後回到第二步

用尺取法來優化,使複雜度降爲了O(n)。

最後,再給一個尺取法的定義以便更好理解:返回的推進區間開頭和結尾,求滿足條件的最小區間的方法稱爲尺取法。

其實,個人覺得這種方法稱之爲蚯蚓法更好,像蚯蚓一般一點一點的先縮起來蓄勢再往前移動。

至於代碼,已經貼出來過,再貼一次吧

#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int maxn=100010;
int num[maxn];
int n,S;

int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&S);
        for(int i=1;i<=n;i++)
            scanf("%d",&num[i]);
        int sum=0,head=1,p=1;
        int ans=n+1;
        for(;;)
        {
            while(p<=n&&sum<S)
                sum+=num[p++];
            if(sum<S)
                break;
            ans=min(ans,p-head);
                sum-=num[head++];
        }
        if(ans==n+1)
            cout<<0<<endl;
        else
            cout<<ans<<endl;
    }
  return 0;
}

分析
用sum累加sum數組找到第一個滿足sum>=S的sum[i]的 p 值,再依次縮小起始地址 head 到 p 的距離,獲得一個 p-head 的值然後再將 p 值後移重複上述操作。

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