測試手機
x星球的居民脾氣不太好,但好在他們生氣的時候唯一的異常舉動是:摔手機。
各大廠商也就紛紛推出各種耐摔型手機。x星球的質監局規定了手機必須經過耐摔測試,並且評定出一個耐摔指數來,之後才允許上市流通。
x星球有很多高聳入雲的高塔,剛好可以用來做耐摔測試。塔的每一層高度都是一樣的,與地球上稍有不同的是,他們的第一層不是地面,而是相當於我們的2樓。
如果手機從第7層扔下去沒摔壞,但第8層摔壞了,則手機耐摔指數=7。
特別地,如果手機從第1層扔下去就壞了,則耐摔指數=0。
如果到了塔的最高層第n層扔沒摔壞,則耐摔指數=n
爲了減少測試次數,從每個廠家抽樣3部手機參加測試。
某次測試的塔高爲1000層,如果我們總是採用最佳策略,在最壞的運氣下最多需要測試多少次才能確定手機的耐摔指數呢?
請填寫這個最多測試次數。
注意:需要填寫的是一個整數,不要填寫任何多餘內容。
題意
①、耐摔指數:如果手機從第7層扔下去沒摔壞,但第8層摔壞了,則手機耐摔指數=7。
②、測試手機個數:每個廠家抽樣3部手機參加測試。換句話說,在將3部手機摔壞後,一定要測試出該廠家手機耐摔指數。
③、題目設定情景:我們總是採用最佳策略,在最壞的運氣下最多需要測試多少次才能確定手機的耐摔指數。
誤區:二分選層
在題目理解上錯誤的話,很容易以爲該題每次測試都選擇在未測試層數中,居中的那層。
eg:在1000層爲測試層數內,選擇第500層作爲開始測試的層數。這樣我們就會得到在塔高爲1000層的情況下,測試10次就能得到手機耐摔指數,這個結果是有問題的,不符合題目設定情景。
在題目設定情景下,若選擇以第500層作爲開始測試的層數,能測試10次就得到手機耐摔指數嗎?
測試次數 | 測試層數 | 手機測試結果 |
---|---|---|
1 | 500 | 壞 |
2 | 250 | 壞 |
3 | 125 | 壞 |
4 | 67 | (沒手機可以測試) |
通過上面的表格,可以看出在題目給定的情景下,不能通過二分的方式來查找手機耐摔指數。
解題思路:遞推
①、有一部手機可用於測試的情況:
在最壞運氣的情況下,有多少層就應該測多少次。
eg:假設測試的最高層數爲10層,那麼最佳策略應該是測10次。
②、有兩部手機可用於測試的情況:
將1層 ~ n層都作爲起始測試點,每次得到最多的測試次數test。(在測試結果好與壞中取最多的測試次數)。
在由1層 ~ n層得到的n個test中,將最小的test作爲用兩部手機測試n層最佳策略。
③、有三部手機可用於測試的情況:
同求有兩部手機可用於測試的情況大同小異。
④、得到結果:
在最壞運氣、採用最佳策略的情況下,用三部手機測試最高層數爲1000層時的測試次數。
具體請將文字結合代碼一同理解,效果更佳。
#include<bits/stdc++.h>
using namespace std;
int dp[1010][4];
int main()
{
//初始化
dp[1][2]=1;
dp[1][3]=1;
for(int i=1; i<=1000; i++)
dp[i][1]=i;
//遞推
for(int k=2; k<=3; k++) //一共有k部手機
{
for(int sum=2; sum<=1000; sum++) //求第sum層最壞運氣測試次數
{
int min_=1001;
//最壞運氣條件下,尋找k部手機在第sum層的最佳策略(測試次數最少)
for(int i=1; i<=sum; i++) //假設從i層開始測試
{
int good=1+dp[sum-i][k];
//假設測試結果:好 (餘剩sum-i層未測)
//i層最壞運氣測試次數 = 1 + k部手機在第sum-i層最壞運氣測試次數
int bad =1+dp[i-1][k-1];
//假設測試結果:壞 (餘剩i-1層未測)
//i層最壞運氣測試次數 = 1 + (k-1)部手機在第i-1層最壞運氣測試次數
//從第i層開始測試,最壞運氣條件下,測試次數max_
int max_=max(good, bad);
//判斷從i層開始測試得到最壞運氣測試次數是否比min_更小
min_=min(max_, min_);
}
//k部手機在第sum層最壞運氣測試次數
dp[sum][k]=min_;
}
}
cout<<dp[1000][3];
return 0;
}
總結
這道題目邏輯會相對複雜一些。
兩個根本問題:什麼情況下是最壞運氣?怎麼做纔是最佳策略?
另外很容易就掉入二分選層的誤區,認爲二分就是最佳策略。
希望能夠將自己的一些學習經驗分享給有需要的人。
我是小鄭,一個堅持不懈的小白。