有誰能給我【NOIP2015】《跳石頭》的暴力代碼和二分代碼以及其中算法思想的詳細解釋啊?
#include<cstdio>
#include<cstring>
using?namespace?std;
const?int?maxn=50010;
//n,m,L的意義和題目描述中的壹樣,a[]表示每個石頭到起點的距離,方便起見,將終點補充為最後壹塊石頭
int?n,m,L;
int?a[maxn];
//二分了最短跳躍距離?mid之後,開始檢查這個答案mid能不能滿足至多抽走m塊石頭
bool?check(int?mid){
//last表示上壹塊沒有被抽走的石頭離起點的距離 int?last=0,cnt=0; for(int?i=1;i<=n;i++){//如果兩點之間的距離比跳躍距離短,那麽就需要把這壹塊石頭拿走,不然的話就可以不用管。
//當然如果i==n也就是終點的時候是不能拿走終點的,但是這個時候拿掉前壹個石頭也壹定能達成目的,所以不管怎樣只需要拿掉壹個石頭。
//如果不用拿掉的話,上壹塊沒有抽走的石頭就是當前這壹塊了。
if(a[i]-last<mid)?cnt++;
else?last=a[i];
} //如果必須要拿掉的石頭數目<=m個,說明二分出的最短距離可以接受,返回true if(cnt<=m)?return?true; return?false;}
int?main(){
int?ans; scanf("%d%d%d",&L,&n,&m); n++;a[n]=L; for(int?i=1;i<n;i++)?scanf("%d",&a[i]); int?l=0,r=a[n],mid; while(r-l>1){mid=(l+r)>>1;
//如果這個值可以接受,那麽比它小的值都可以接受,二分的下界就可以變成這個新的值
//如果不能接受,那麽比它大的值也不能接受,二分的上界變成這個新的值
if(check(mid))?l=mid;
else?r=mid;
} //當然如果最後區間還剩下兩個的時候,有可能上界也是可以接受的。[其實這種情況只發生在a[n]為最大距離時] if(check(r))?ans=r; else?ans=l; printf("%d",ans); return?0;} 這裏二分思想的使用是因為如果用1表示壹個值可行,0表示壹個值不可行的話。
那麽值域壹定是這樣的:
1111111110000000000
也就是說:比最優值小的壹定都可行,比最優值大的壹定都不可行,這樣的話,我們就可以很快的收斂上下界。使得嘗試的數目變成log2(L)級別。而每次判斷的復雜度是O(n)的,所以得到了滿足時間限制的算法。
其中判斷的部分使用的是貪心的思想,即能放則放,這個思想經常與二分相結合使用。