1. 程式人生 > 其它 >尺取--(毛毛蟲演算法)

尺取--(毛毛蟲演算法)

尺取--(毛毛蟲演算法)
尺取演算法也叫毛毛蟲演算法,因為計算過程有點類似毛毛蟲一點點的往前挪,在挪動的過程中可以得到一些需要的解。(自動腦補)
通過兩個變數來儲存所選取區間的左右端點,然後不斷的推進區間,尋找所需要的答案(尺取的精髓),其實也是一種暴力列舉方法,不過是有技巧的列舉,所以尺取演算法比一般的演算法快的多,尤其是資料量比較大的時候,尺取就顯得非常有用,所以也是acm經常用到的演算法之一。
通過一個例題來理解這個演算法
冬天與火鍋更配
冬日裡的一抹暖陽總是能給人們留下深刻的記憶,人們喜愛冬天的太陽,就跟人們喜愛冬天的火鍋一般。
寒冷的冬天總會讓人想起火鍋,最近小Z特別想去吃火鍋,剛好某家轉轉火鍋剛開業有活動,有n盤火鍋圍成一個圈,第一盤和最後一盤是相連的,每一盤火鍋都有一個價值a[i],現在可以吃連續的m盤火鍋,小Z想知道他所吃的那連續的m盤火鍋的最大價值可以是多少?你能幫幫憨憨的小Z嗎。
輸入格式
第一行數入兩個整數n,m(1<=m<=n<=2000000),分別表示火鍋的盤數和可以吃的連續的盤數
第二行輸入n的數a[i] (1<=a[i]<=100000),分別表示每一盤火鍋的價值
輸出格式
輸出一個整數,表示連續m盤火鍋的最大價值
樣例輸入
5 3
6 1 2 5 3
樣例輸出
14
分析:
這個題實際就是求連續m個數和的最大值,想必很多人也是一開始暴力模擬一遍,然後提交是時間超限,這裡最壞的時間複雜度是O(n^2),這個題的資料量比較大,所以考慮用尺取。
下面看一下核心程式碼

#include<stdio.h>
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int a[n];
        int t=0;//表示推進的m
        int tail=0;//表示毛毛蟲的尾巴
        long long max1=-1;//所求的最大值
       	long long sum=0;
        for(int i=0;i<n;i++)
            scanf("%d",a+i);
        while(1)//尾巴不爬到最後就一直往前爬
        {
            while(t<m)//毛毛蟲向前爬m個位置
            {
                int tt=tail+t;
                if(tt>=n)//頭爬到最後得到第一個位置去
                    tt%=n;
                sum+=a[tt];
                t++;
            }
            if(sum>max1)max1=sum;
            sum-=a[tail];//得到一次連續m個數和之後減去尾巴的值
            tail++;//尾巴向前挪一個
            if(tail==n-1)break;//如果尾巴到了最後一個就可以退出了
            t--;//長度減一(尾巴)
        }
        printf("%lld\n",max1);
    }
}

可以看出尺取把原來的時間複雜度O(n2)變成了O(n),在效率上得到了很多的提高。