poj 3783 Balls 动态规划 100层楼投鸡蛋问题
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4098409.html
题目链接:poj 3783 Balls 动态规划 100层楼投鸡蛋问题
使用动态规划算法,使用$dp[i][j]$表示对于i层楼并拥有$j$个鸡蛋时能够判断鸡蛋质量需要的最少次数。
假如我们在第$k$层扔下一个鸡蛋,则有两种情况,如果鸡蛋没有损坏则问题相当于我们对于$i-k$层楼拥有$j$个鸡蛋所需的最少的次数。
如果鸡蛋损坏了,则问题相当于对于k层楼拥有$j-1$个鸡蛋的最小次数。从而可以得到动态规划公式:
\begin{equation}
dp[i][j] = Min(Max(dp[k][j-1],dp[i-k][j])),k\in[1,i)
\end{equation}
数学方法推倒:
如果我们有$2$个鸡蛋,$k$次投掷机会,那么第一次在$k$层投掷,如果坏掉,则从第一层往上投。
否则剩下$k-1$次机会,所以要在$k+(k-1)$层投掷,如此往复,两个腕带可以投掷的最高楼层为:
\begin{equation}
\sum_{i=1}^k i = \frac{k(k+1)}{2}
\end{equation}
对于三个鸡蛋k次机会,根据上面的结论,两个鸡蛋$k-1$次可以测试$k(k-1)/2$层楼,所以第一次在$k(k-1)/2+1$层投,如果坏掉,则从第一层往上投。
否则剩下k-1次机会和两个鸡蛋,则在此基础上增加$(k-1)(k-2)/2+1$层投掷,如此往复。三个鸡蛋可以投掷的最高层为:
\begin{equation}
\sum_{i=1}^k \frac{i(i-1)}{2}+1 = \frac{k^3+5k}{6}
\end{equation}
代码如下:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <cstring> 5 #include <limits.h> 6 #define MAX_F 1001 7 #define MAX_E 100 8 using namespace std; 9 int dp[MAX_F][MAX_E]; 10 int solve(int floor, int egg) 11 { 12 memset(dp, 0, sizeof(dp)); 13 for( int i = 1 ; i <= floor ; i++ ) 14 { 15 dp[i][1] = i-1; 16 } 17 for( int i = 1 ; i <= egg ; i++ ) 18 { 19 dp[1][i] = 0; 20 } 21 for( int i = 2 ; i <= floor ; i++ ) 22 { 23 for( int j = 2 ; j <= egg ; j++ ) 24 { 25 int tmp = INT_MAX; 26 for( int k = 1 ; k < i ; k++ ) 27 { 28 tmp = min(tmp, max(dp[k][j-1] , dp[i-k][j])); 29 } 30 dp[i][j] = tmp+1; 31 } 32 } 33 return dp[floor][egg]; 34 } 35 int main(int argc, char *argv[]) 36 { 37 int t; 38 scanf("%d", &t); 39 while( t-- ) 40 { 41 int n, egg, floor; 42 scanf("%d%d%d", &n, &egg, &floor); 43 printf("%d %d\n",n, solve(floor, egg)); 44 } 45 }