1. 程式人生 > >【暑假集訓筆記】尺取法簡介

【暑假集訓筆記】尺取法簡介

/**尺取法
尺取法:顧名思義,像尺子一樣取一段,尺取法通常是對陣列儲存一對下標,
即所選取的區間的左右端點,然後根據實際情況不斷地推進區間左右端點以得出答案。

eg:
給定一個序列(整數),找出最短的子序列長度,使得其和大於或等於S。

問題:
1、什麼情況下能使用尺取法? 
	所求解的答案在區間內連續;在通過判斷之後,區間的移動有明確的方向(一般是起點到終點)
2、何時推進區間的端點? 
	如上題:如果大於S左端點移動,如果小於S右端點移動遍歷這個區間即可。
3、如何推進區間的端點? 
	下表指標移動
4、何時結束區間的列舉?
	此題來說是遍歷完成,也有可能是達到條件返回真即可。

總之:區間左右端點一般從最整個陣列的起點開始,
	之後判斷區間是否符合條件在根據實際情況變化區間的端點求解答案。
	

*/
#include <iostream>
#include <cstdio>
using namespace std;

const int inf = 0x3f3f3f3f;
int  a[10000]; 

int main()
{
	int n,S;
	cin>>n>>S;
	for(int i = 0;i<n;i++)	scanf("%d", &a[i]);
	//尺取法:
	int res = inf;//答案:滿足條件的最小長度
	int start=0,end=0;//左右指標
	int sum = 0;//用於與S判斷的臨時 和變數 
	while(1){//尺取 
		//求得一個滿足條件的sum
		while(sum<S && end<n)//sum求得就跳出,下表越界就跳出
		{
			//此過程是右指標後移 
			sum += a[end];
			end++; 
		} 
		//如果是因為遍歷完成(因為sum<S滿足條件,只能是end<n不滿足)而跳出的while,那麼就不用進行下方的操作 
		if(sum<S)	break; 
		
		res = min(res,end-start);//最小區間
		
		//更新右端點 
		sum-=a[start];
		start++;  
	} 
	if(res == inf)//無解情況
		cout<<"0"<<endl;
	else
		cout<<res<<endl; 
	return 0;
}