1. 程式人生 > >扔雞蛋

扔雞蛋

() max 比較 兩種 一件事 memset cpp 雞蛋 open

Description

Jzj要來做一個經典的實驗:測試雞蛋殼的堅硬程度。

Jzj正好處於N層高的摩天大樓中,所以通過從某一樓層向下扔雞蛋來測試雞蛋殼的堅硬程度。

Jzj有M個雞蛋,所有的雞蛋硬度都一樣。如果雞蛋從第L層摔下去沒有碎,而在L+1層摔碎了,那麽稱雞蛋的硬度是L。嗯,反正jzj不喜歡吃雞蛋,所以不用擔心浪費的問題。大樓共有N層高,如果在N層還沒有摔碎,就認為硬度是N;如果在第1層就碎了,硬度為0。

雖然jzj不喜歡吃雞蛋,但是jzj的好朋友yk特別喜歡吃雞蛋。為了幫好朋友保護可憐的小雞蛋,jzj想知道用這麽多雞蛋,最少摔幾次就可以保證測試出它們的硬度。

Analysis

一開始想到了二分,每次都選擇樓層中間扔,啪嘰碎掉之後長度縮減一半,直到只剩一個雞蛋每層試扔一次。

但是我忽視了一個問題。首先明白一件事情,對於高度大於1的樓層,雞蛋越多越好。那麽在這個前提下探究這個問題,如果在低於中間部分的樓層扔雞蛋,有兩種情況,碎和不碎。

  • 如果不碎,那麽多一個雞蛋探索更多的樓層也未嘗不會更優
  • 如果碎了,那麽碎掉一個雞蛋卻可以只用探究更少的樓層

那麽低樓層絕對存在優於中間樓層的情況,而高樓層無需分析,理由同上。

所以只能采用動態規劃了,因為不具有有序性無法二分所以對於i層樓只能枚舉1到i/2層樓,尋找max(dp[j-1][k-1],dp[i-j][k])的最小值即可。

為了方便,遞歸比較好寫。

Code

#include <bits/stdc++.h>

int m,n,dp[1010][1010];

int search(int h,int e){
    if(e==1)return dp[h][e]=h;
    if(!h)return 0;
    if(dp[h][e]<0x3f3f3f3f)return dp[h][e];
    for(int i=1;i<=h/2+1;i++)
        dp[h][e]=std::min(dp[h][e],std::max(search(i-1,e-1),search(h-i,e))+1);
    return dp[h][e];
}

int main(){
    freopen("eggs.in","r",stdin);
    freopen("eggs.out","w",stdout);
    std::cin>>m>>n;
    memset(dp,0x3f3f3f3f,sizeof(dp));
    std::cout<<search(n,m)<<std::endl;
    return 0;
}

扔雞蛋