XDU 易碎的鸟蛋(鹰蛋实验) Dp问题

来源:互联网 发布:三星手机mac地址查询 编辑:程序博客网 时间:2024/04/29 21:08

题目链接:http://acm.xidian.edu.cn/problem.php?id=1007

题意:给定鸟蛋的数目和楼层数,确定鸟蛋的硬度。

这应该是一个比较经典的Dp了,看了别人朱晨光的论文,也就只能写个N^2 long N的算法了。

朱晨光论文链接

这篇文章让我懂了 log N的意思:鹰蛋实验

自己的理解:首先题目给定的有两个变量,我们可以很容想到一个式子:dp[i][j],但是,该如何对这个式子进行状态定义呢?用dp[i][j]表示:用i个鸟蛋进行楼层数为j(实际上楼层的最高层也就是j层了)的实验所需要的最多次数(就是题目要求的)。那么状态转移是怎样的呢?显然,第j层已经是最上面的那层了,那么在进行第j层实验之前,肯定会由下面的某个层转移得到,到底是那个层,我们并不确定,那么,我们就枚举j前面的每一个层就行了,假设其中一个楼层为w(w<=j),则用两种情况:

一:从第w层丢下去的鸟蛋破了,则dp[i][j]只能由w层下面的层数来决定:鸟蛋数为i-1,楼层数为w-1的实验来决定,这就是一个子问题了。

二:从第w层丢下去的鸟蛋没有破,则dp[i][j]只能由w层上边的层数来决定了,也就是:鸟蛋数为i,楼层数为j-w的实验决定,这又是一个子问题。

所以可以得到一个状态转移方程:

dp[i][j]=min(max{dp[i-1][w-1],dp[i][j-w]}+1,dp[i][j])

仔细一看,这里需要枚举单个变量i,j,w,时间复杂度达到了O(N^3)。下面就是对其简单优化的思想:

首先假设我们有无穷多个鸟蛋,进行楼层数为N的实验,显然不管结果如何(0,1,2......N),我们都可以通过模拟二分查找得到(因为鸟蛋无数个),所以最多需要log N次左右,这里N最大为1000,即:log 1000=9.几,所以最多需要10次,也就是10个鸟蛋即可通过二分查找找到所有情况的解。也就是说,只要鸟蛋达到了10个,就可以完全模拟二分查找了。这不知不觉就把鸟蛋数从1000降到了10,这复杂度降的可不少啊,O(N)-->O(log N)。最后的时间复杂度为:O(10^7),打表一次就够了。


代码:

#include<iostream>#include<cstdio>#include<algorithm>#define maxn 1010#define INF 0x7fffffffusing namespace std;int dp[maxn][maxn];//如分析所述int n,k;int main(){    for(int i=0;i<=1000;i++) for(int j=0;j<=1000;j++) dp[i][j]=INF;//初始化    for(int i=0;i<maxn;i++) dp[1][i]=i;//初始化    for(int i=0;i<maxn;i++) dp[i][0]=0;//初始化    for(int i=2;i<=10;i++)//log N 级别        for(int j=1;j<=1000;j++)            for(int w=1;w<=j;w++)                dp[i][j]=min(max(dp[i-1][w-1],dp[i][j-w])+1,dp[i][j]);    while(scanf("%d %d",&n,&k)==2){        if(n>10) n=10;        printf("%d\n",dp[n][k]);    }    return 0;}


0 0