首页 > 其他分享 >【动态规划】【换维】扔鸡蛋游戏

【动态规划】【换维】扔鸡蛋游戏

时间:2023-09-14 22:24:36浏览次数:31  
标签:游戏 int 鸡蛋 高度 long 换维 ll dp

【动态规划】【换维】扔鸡蛋游戏

这是一道在《信息学奥赛一本通》上的经典题目。题目描述如下:

有 \(k\) 个一模一样的鸡蛋,楼的高度为 \(n\) ,定义鸡蛋的硬度为 \(x\) ,当且仅当将鸡蛋从 \(x\) 楼扔下不会碎,从 \(x + 1\) 楼扔下会碎,求最坏情况下求出鸡蛋硬度的最小步数。

\(k \leq 10,n \leq 100\) 。保证硬度在 \([0,n]\) 之间。

考虑假设只有两个蛋,最小步数是 \(t\) ,我们的策略是怎样的:

image

我们一定是分块来扔,考虑如果第一次碎了,那么硬度一定小于第一次扔的高度,此时我们还有 \(t - 1\) 次,可以确定 \(t - 1\) 个位置(扔 \(1\) 到 \(t - 1\) ,如果 \(1\) 碎了就是 \(0\)),所以第一次的高度选为 \(t\) 。后面同理,只不过每次都比上一次少了 \(1\) 。最后能确定的高度上限是 \(\frac {t(t + 1)}2\) 。

接下来假设我们有 \(3\) 个蛋,假设第一次高度为 \(x\) 。如果碎了,我们就要用 \(2\) 个蛋和 \(t - 1\) 次来确定剩下的高度,假设 \(f_{i,j}\) 为 \(i\) 个蛋 \(j\) 次能达到的高度。这个高度 \(x\) 就等于 \(f_{2,t - 1} + 1\) 。如果没碎,我们就要用 \(3\) 个蛋和 \(t - 1\) 次确定上面的高度,所以是 \(f_{3,t - 1}\) 。

综上所述, \(dp\) 式子已经很完全了,就是:

\[f_{i,j} = f_{i - 1,j - 1} + 1 + f_{i,j - 1} \]

直接做即可,这道题目难以通过枚举高度和鸡蛋个数来算出次数,所以我们考虑换一维,用个数和次数推出最高高度,再通过二分回答询问,是一种很巧妙的思路,时间复杂度 \(\Theta(kn)\) 。

当然还有基于枚举高度的 \(\Theta(n^2k)\) 的做法,设 \(f_{i,j}\) 为硬度在 \([0,i]\) 之间,还有 \(j\) 个鸡蛋时的最小次数,我们每次枚举中间在哪个位置扔一次,答案就是碎和不碎两种情况的 \(max\) ,再将所有枚举的情况取 \(min\) 。

\[dp_{i,j} = \min \{dp_{i,j},\max\{dp_{k - 1,j - 1},dp_{i - k,j}\} + 1\} \]

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,dp[101][101];//dp[i][j]:硬度在[0,i]之间,还有J个鸡蛋
int main()
{
	while(cin>>n>>m)
	{
		memset(dp,0x3f,sizeof(dp));
		for(int i=1;i<=n;i++)
			dp[i][1]=i;//只有一个鸡蛋,扔i次
		for(int i=1;i<=m;i++)
			dp[1][i]=dp[0][i]=1;//硬度只有2种情况,只扔1次
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				for(int k=1;k<=i;k++)
					dp[i][j]=min(dp[i][j],max(dp[k-1][j-1],dp[i-k][j])+1);
		cout<<dp[n][m]<<endl;
	}
	return 0;
 }

如果这题数据加强到 \(10^{18}\) 我们怎么做呢?

考虑到 \(k \geq \lceil\log n\rceil\) 时,我们只需要二分来扔鸡蛋,就是最优选择。

鸡蛋数很少时,我们沿用第一种 \(dp\) 方程,发现 \(f_i(j)\) 是一个关于 \(j\) 的多项式,由于每次 \(f_i\) 近似于 \(f_{i - 1}\) 的前缀和,所以每次次数增加 \(1\) ,这是一个 \(i\) 次多项式,我们求的多项式次数很小,只有大约 \(64\) 次,但是自变量很大,可以达到 \(10^{18}\) 。提前计算次数 \(+ 1\) 个值后每次询问拉格朗日插值即可。

#include<bits/stdc++.h>
using namespace std;
const int N = 105;
typedef long long ll;
const ll inf = 1000000000000000005;
long long f[N][N];
inline void prework()
{
	for(int i = 1;i <= 60;i++) f[1][i] = i;
	for(int i = 2;i <= 58;i++)
	{
		f[i][1] = 1;
		for(int j = 2;j <= 60;j++)
			f[i][j] = f[i - 1][j - 1] + 1 + f[i][j - 1];
	}
} 
inline long double lag(ll p,ll X)
{
	long double jdg = 0;
	for(int i = 1;i <= p + 1;i++)
	{
		long double now = f[p][i];
		for(int j = 1;j <= p + 1;j++) 
		{
			if(j == i) continue;
			now *= 1.00 * (X - j) / (i - j);
		}
		jdg += now;
		if(jdg > inf) return inf;
	}
	return jdg;
}
inline ll lg(ll x)
{
	ll ret = 1;
	if((x & (-x)) == x) --ret;
	for(;x;x /= 2) ++ret;
	return ret;
}
int main()
{
	long long n,k;
	prework();
	while(cin>>n>>k)
	{
		if(k == 1) {cout<<n<<endl; continue;}
        if(k >= 59)
    	{
    		cout<<lg(n);
	    	continue;
	    }
		int l = 1,r = 4000005;
		while(l < r)
		{
			int mid = (l + r) >> 1;
			if(lag(k,mid) < n) l = mid + 1;
			else r = mid;
		}
		cout<<l<<endl; 
	}
	return 0;
}

之所以二分上界是 \(4 \times 10^6\) 是因为 \(k \geq 2\) 时答案不会超过这个数字,插值时如果当前答案大于 \(inf\) 就直接返回 \(inf\) 因为最终要做的只是比大小。

当然这题可以前缀和优化 \(dp\) 到 \(\Theta (n)\) ,然后直接 \(dp\) 到 \(4 \times 10^6\) ,只有 \(k = 2\) 时会接近这个数字,其他的都远小于,所以也可以做。

标签:游戏,int,鸡蛋,高度,long,换维,ll,dp
From: https://www.cnblogs.com/TheLastCandy/p/17703673.html

相关文章

  • 【9月福利周】邀好友共领新人福利,茶具/游戏鼠标“2选1”
    嘿,9月福利周来啦~今日起,邀请好友在51CTO博客成功发布第一篇原创技术文章,你和好友都有福利!(含代码400字以上必有奖)活动时间活动时间:9月14日-9月20日(共7天)活动福利活动页面:点击此处>>>累计邀请人数好友奖励你的奖励3人大号鼠标垫茶具(一壶两杯)50人罗技游戏鼠标G502邀请流程1、邀请朋......
  • 弹幕游戏直播新玩法疯狂吸金
      弹幕游戏直播新玩法:疯狂吸金方法  一、弹幕互动玩法  在直播间互动过程中,所有的用户都是其中的一员,只要在直播间发出一个字就可以参与其中,加入阵营。一旦成为一方阵营,只需轻点屏幕、点个赞或打出一个666,就可以成功招募出一个基础兵种,而你的大名也会在屏幕上显示出......
  • 弹幕小游戏源码设计重点解析
      弹幕小游戏开发的特点就是以互动性和与类型为主,更重要的还是以钱赚,在开发设计弹幕游戏时需要注意那些要点:  1.弹幕游戏的UI设计:弹幕小游戏的UI需要简洁明了,易于操作。重点需要设计一个直观、快速的交互方式,使用户能够轻松参与并理解游戏规则。  2.弹幕游戏逻辑设计......
  • 怎么搭建弹幕互动游戏直播
      一、直播间的用户吸引  1.确定好直播间的标题,直播间的主题内容,互动语言。  2.准备好直播所需的数据后台、游戏软件、麦克风等设备和声卡话筒,并确保其能够正常工作。  3.在直播间内放置一些有趣的弹幕互动游戏,吸引观众参与。  二、安装弹幕互动游戏 ......
  • 弹幕互动游戏开发定制
      弹幕互动游戏开发定制功能介绍  弹幕互动游戏软件开发,想要开发定制一款具有创意性的游戏软件,那就先确定好游戏的玩法,游戏的UI设计,盈利方式。这种游戏的玩法就是适合在直播间玩,互动性强,增加游戏的趣味性。  弹幕游戏的开发,功能主要是以互动性,游戏界面的娱乐效果,开发......
  • 弹幕互动游戏直播软件
      弹幕互动游戏是一种以在直播间互动的游戏软件,通过进来的用户发送文字实现对方的阵地占领,这种新型的直播方式不仅可以让观众更加深入地参与到游戏过程中,还可以让主播更好地了解观众的需求和反馈。  弹幕游戏软件主要就是用户参与越多,越有意思,观众可以在直播过程中发送弹......
  • 领地占领弹幕互动小游戏开发需求
      直播间弹幕占领土地面积游戏,该款游戏可以是射击或者的吞噬占领方式的互动功能游戏。玩家通过直播间的说明,加入游戏控制自己的角色,在自己的领地向对方领地,占领对方的土地实现胜利。玩家还可以通过发送弹幕与其他玩家进行实时互动,共同完成任务。  1.游戏玩法  在直播......
  • 1.游戏模型制作标准
    一.max的基础操作1.试图区 顶视图 T 前视图 F 这三个都是辅助视图(尽量不要做旋转操作) 左视图 L 透视图 P 操作视图''' 视图最大化 alt+w 模型居中显示 Z 边框显示 J 取消网格显示 G 大师模式 ctrl+x'''2.显示模式线框和实体之间的切换 F3实体 + 线......
  • Unity 游戏开发、02 基础篇 | 知识补充、简单使用动画、动画状态机
    前置笔记(由浅入深)Unity游戏开发、01基础篇2场景操作3D场景Q手型工具(鼠标中键):上下左右移动场景ALT+鼠标左键:以视图为中心旋转鼠标右键:以观察者为中心旋转SHIFT+Gizmo方块:Y轴归位物体节点+F:观察者定位至物体窗口布局3D项目一般窗口布局如下3全局光照全......
  • AI打游戏-壹
    前言AI打游戏-壹(bilibili)背景大部分AI教程专注算法训练,使用开源训练集进行训练实际工作中,算法训练只是一部分,还有很多上下游的工作通过AI打游戏这个主题,来熟悉AI产业全貌说明提到AI是标题党,这次使用的不能算人工智能,只是目标检测(YOLO)的简单应用,并不是强化学习这类......