尺取(轉)

轉載自http://blog.chinaunix.net/uid-24922718-id-4848418.html

有這麼一類問題,需要在給的一組數據中找到不大於某一個上限的“最優連續子序列”

於是就有了這樣一種方法,找這個子序列的過程很像毛毛蟲爬行方式比較流行的叫法是“尺取法”。

Poj3061

給長度爲n的數組和一個整數m,求總和不小於m的連續子序列的最小長度

輸入

n = 10m = 15

5 1 3 5 10 7 4 9 2 8

輸出

2

那麼我們先用sum存當前這個子序列的和,從左邊第一個數來存,直到這個子序列的和大於等於m爲止,再記錄下當前長度。

其實相當於當不滿足條件就入隊,然後得到隊列長度,再將隊首元素出隊,再進行下一次的入隊,直到滿足條件再次出隊,並且將這一次的長度與歷史最短長度進行取捨,最後掃到最後的元素卻無法再滿足入隊條件的時候就結束,此時用O(n)的時間就可以得到答案。

如下,我把樣例用毛毛蟲爬一遍,紅色的是當前“毛毛蟲着地”也就是剛好滿足題意的子序列的地方:

 

 

5 1 3 5 10 7 4 9 2 8

 

1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8

 

5 1 3 5 10 7 4 9 2 8




//代碼如下

#include<stdio.h>
int MIN(int x,int y)
{
	return x>y?y:x;
}
int main()
{
	int n,mmax,ans,i,j,sum,m,a[10000];
	scanf("%d",&m);
	while(m--)
	{
		
		scanf("%d%d",&n,&mmax);
	
		for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	
		ans=n+1; //步數
		i=0;
		j=0;
		sum=0; 
	
		while(1)
		{
			while(j<n&&sum<=mmax)  //滿足條件一直sum+
			sum+=a[j++];
	
			if(sum<mmax)break; //證明j>n 但是 sum<mmax -->沒有滿足條件的長度
			ans=MIN(j-i,ans);  //滿足條件,ans-->步數的最小值
			sum-=a[i++];   //類似於出隊
		}
	
		if(ans>n)
		ans=0;
	
		printf("%d\n",ans);
	
		
	}
	
	
	
}





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