高楼扔鸡蛋

动态规划:高楼扔鸡蛋:


题目:
*你面前有一栋从 1 到N共N层的楼,然后给你K个鸡蛋(K至少为 1)。现在确定这栋楼存在楼层0 <= F <= N,在这层楼将鸡蛋扔下去,鸡蛋恰好没摔碎(高于F的楼层都会碎,低于F的楼层都不会碎)。现在问你,最坏情况下,你至少要扔几次鸡蛋,才能确定这个楼层F呢? *
思考点:
dp min res=是对每一层都算一下,求最小次数
用字典做备忘录不错,但这里用数组也可,而且不用这种方法?剪枝?,会爆炸
但每一次[递归的每一层]又要取最大值,因为最坏情况
有两个错误:忘写了等于号,和记录防止重复计算的数组应写在循环外面

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
struct aa{
int k;
int n;
};
map<aa,int>dic;
int dic2[1000][1000]={0};
int dp(int k,int n){
    if(k==1){
        return n;
    }if(n==0){
        return 0;
    }
  //  if(dic[{k,n}]){
  //      return  dic[{k,n}];
  //  }
  if(dic2[k][n]!=0){
    return dic2[k][n];
  }
    int res=10000;
    for(int i=1;i<=n;i++)
    {
        int dpsui,dpweisui;
        ///等价于下面的模块留下来因为出错了
        dpsui=dp(k-1,i-1);
        dpweisui=dp(k,n-i);
        if(dpsui>=dpweisui){///要写等于号
            res=min(res,dpsui+1);
           // dic[{k,n}]=res;
        }
        if(dpsui<dpweisui){
            res=min(res,dpweisui+1);
           // dic[{k,n}]=res;
        }
        ///等价于上面的模块
    ///res=min(res,max(dp(k,n-i),dp(k-1,i-1))+1);
    }
    dic2[k][n]=res; ///应该写在循环外面
    return res;
}
int main()
{
    int k=2,n=100;
    cout<<dp(k,n);
    return 0;
}

2020.9.10写出来的代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int dp[105][105]={0};
int finder(int k,int n){/k:jidanshu n:loucengshu

if(dp[k][n]!=0){return dp[k][n];}
if(n==0)return 0;
if(k==1)return n;

int res=10000;
zuo:suile you:meisui
for(int i=1;i<=n;i++){
    res=min(res,max(finder(k-1,i-1),finder(k,n-i))+1);
}
dp[k][n]=res;
return res;
}
int main()
{
    cout<<finder(2,100);
    return 0;
}


2020.11.13

#include <iostream>
#include<bits/stdc++.h> 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
#define maxn 10005
int mem[maxn][maxn]={0};

int dp(int k,int n)
{
	if(k==1)
	{
		return n;
	}
	if(n==0)
	{
		return 0;
	}
	
	
	if(mem[k][n]!=0)
	{
		return mem[k][n];
	}
	
	int res=maxn;
	for(int i=1;i<=n;i++)
	{
		res=min(res,max(//这样也能过编译 
		dp(k-1,i-1),//sui//错误原因,这里之前没i-1 
		dp(k,n-i))+1//unsui
		);
	}
	mem[k][n]=res;
	return mem[k][n]; 
}

int main(int argc, char** argv) {
	cout<<dp(2,100);
	return 0;
}//out::14 

高楼鸡蛋进阶

高楼鸡蛋进阶

在这里插入图片描述

二分优化

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
struct aa{int k;int n;};
map<aa,int>dic;
int dic2[1000][1000]={0};
int dp(int k,int n){
    if(k==1){return n;}if(n==0){return 0;}if(dic2[k][n]!=0){return dic2[k][n];}
    int res=10000;
    int lo,hi,mid;
    lo=1;
    hi=n;
    ///二分法查找
    while(lo<=hi){
        mid=(lo+hi)/2;
        int broken=dp(k-1,mid-1);
        int un_broken=dp(k,n-mid);
        if(broken>un_broken){
            hi=mid-1;
            res= min(res,broken+1);///res仍需要不断更新(要最小)
            continue;
        }
        if(broken<un_broken){
            lo=mid+1;
            res=min(res,un_broken+1);
            continue;
        }
        if(broken==un_broken){///这里可认为恰好找到了,直接回,而且直接在上面随便一个加等号也可以
            res=min(res,broken+1);
            dic2[k][n]=res;
            return res;
        }
    }
    dic2[k][n]=res; ///应该写在循环外面
    return res;
}
int main()
{
    int k=2,n=100;
    cout<<dp(k,n);
    return 0;
}


2020.9.10重写了一个,上次的代码全有return,浪费了,又写出了个bug(应该是最坏情况(v2)),标好了
(v2里没用min,原代码用了,咋说,也没出问题,)
v1

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int dp[105][105]={0};
int finder(int k,int n){/k:jidanshu n:loucengshu

if(dp[k][n]!=0){return dp[k][n];}
if(n==0)return 0;
if(k==1)return n;

int res=10000;
int le,ri,mid,sui,wei_sui;
zuo:suile you:meisui
le=1;
ri=n;
while(le<=ri)
{
    mid=(le+ri)/2;
    sui=finder(k-1,mid-1);
    wei_sui=finder(k,n-mid);
    ///zuididian

    if(sui<wei_sui){///(zuo)
        le=mid+1;
        res=min(res,wei_sui+1);
        continue;
    }
    if(sui>wei_sui)
    {
        ri=mid-1;
        res=min(res,sui+1);
        continue;
    }
    if(sui==wei_sui)
    {
        printf("yes");
        res=min(res,sui+1);
        break;
    }
}
dp[k][n]=res;
return res;
}
int main()
{
    cout<<finder(2,100);
    return 0;
}

2020.9.10v2

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int dp[105][105]={0};
int finder(int k,int n){/k:jidanshu n:loucengshu

if(dp[k][n]!=0){return dp[k][n];}
if(n==0)return 0;
if(k==1)return n;

int res=10000;
int le,ri,mid,sui,wei_sui;
zuo:suile you:meisui
le=1;
ri=n;
while(le<=ri)
{
    mid=(le+ri)/2;
    sui=finder(k-1,mid-1);
    wei_sui=finder(k,n-mid);
    ///zuididian

    if(sui<wei_sui){///(zuo)
        le=mid+1;
        res=wei_sui+1;///这里要选大的那一个
        continue;
    }
    if(sui>wei_sui)
    {
        ri=mid-1;
        res=sui+1;///这里要选大的那一个
        continue;
    }
    if(sui==wei_sui)
    {
        printf("yes");
        res=sui+1;
        break;
    }
}
dp[k][n]=res;
return res;
}
int main()
{
    cout<<finder(2,100);
    return 0;
}

重定义状态转移(我感觉上次应该是忘写了)

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
struct aa{int k;int n;};
map<aa,int>dic;
int dic2[1000][1000]={0};
int dp(int k,int n){
    if(k==1){return n;}if(n==0){return 0;}if(dic2[k][n]!=0){return dic2[k][n];}
    int res=10000;
    int lo,hi,mid;
    lo=1;
    hi=n;
    ///二分法查找
    while(lo<=hi){
        mid=(lo+hi)/2;
        int broken=dp(k-1,mid-1);
        int un_broken=dp(k,n-mid);
        if(broken>un_broken){
            hi=mid-1;
            res= min(res,broken+1);///res仍需要不断更新(要最小)
            continue;
        }
        if(broken<un_broken){
            lo=mid+1;
            res=min(res,un_broken+1);
            continue;
        }
        if(broken==un_broken){///这里可认为恰好找到了,直接回,而且直接在上面随便一个加等号也可以
            res=min(res,broken+1);
            dic2[k][n]=res;
            return res;
        }
    }
    dic2[k][n]=res; ///应该写在循环外面
    return res;
}
int main()
{
    int k=2,n=100;
    cout<<dp(k,n);
    return 0;
}


2020.9.10更新·

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int dp[105][105]={0};
int finder(int k,int n){/k:jidanshu n:loucengshu
int m=0;

while(dp[k][m]<n){
    m++;
    for(int kk=1;kk<=k;kk++)
    {
        dp[kk][m]=dp[kk][m-1]+dp[kk-1][m-1]+1;

    }
}

return m;

}
int main()
{
    int k,n;
    cin>>k>>n;
    cout<<finder(k,n);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值