首页 > 试题广场 >

丢棋子问题

[编程题]丢棋子问题
  • 热度指数:566 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
一座大楼有层,地面算作第0层,最高的一层为第N层。已知棋子从第0层掉落肯定不会摔碎,从第i层掉落可能会摔碎,也可能不会摔碎()。给定整数N作为楼层数,再给定整数K作为棋子数,返回如果想找到棋子不会摔碎的最高层数,即使在最差的情况下扔的最小次数。一次只能扔一个棋子。
[要求]
时间复杂度在最坏情况下为

输入描述:
输入两个数N, K


输出描述:
输出一个数表示答案。
示例1

输入

10 1

输出

10

说明

因为只有1棵棋子,所以不得不从第1层开始一直试到第10层,在最差的情况下,即第10层是不会摔坏的最高层,最少也要扔10次
示例2

输入

3 2

输出

2

说明

先在2层扔1棵棋子,如果碎了,试第1层,如果没碎,试第3层
示例3

输入

105 2

输出

14

说明

第一个棋子先在14层扔,碎了则用仅存的一个棋子试1~13层
若没碎,第一个棋子继续在27层扔,碎了则用仅存的一个棋子试15~26层
若没碎,第一个棋子继续在39层扔,碎了则用仅存的一个棋子试28~38层
若没碎,第一个棋子继续在50层扔,碎了则用仅存的一个棋子试40~49层
若没碎,第一个棋子继续在60层扔,碎了则用仅存的一个棋子试51~59层
若没碎,第一个棋子继续在69层扔,碎了则用仅存的一个棋子试61~68层
若没碎,第一个棋子继续在77层扔,碎了则用仅存的一个棋子试70~76层
若没碎,第一个棋子继续在84层扔,碎了则用仅存的一个棋子试78~83层
若没碎,第一个棋子继续在90层扔,碎了则用仅存的一个棋子试85~89层
若没碎,第一个棋子继续在95层扔,碎了则用仅存的一个棋子试91~94层
若没碎,第一个棋子继续在99层扔,碎了则用仅存的一个棋子试96~98层
若没碎,第一个棋子继续在102层扔,碎了则用仅存的一个棋子试100、101层
若没碎,第一个棋子继续在104层扔,碎了则用仅存的一个棋子试103层
若没碎,第一个棋子继续在105层扔,若到这一步还没碎,那么105便是结果

备注:
保证最后答案在long long范围内

这题关键是在变换思路,将原问题中的最少需要几次变换成,拥有i个棋子,扔j次最多可以测试出多少楼高,所以状态转移方程可以写成:

dp[i][j] = d[i][j-1] + dp[i-1][j-1] + 1
图片说明

n, k = map(int, input().split())
l = [i for i in range(n+1)]
if k == 1:
    print(n)
else:
    sign = False
    floor = 2
    while True:
        tmp = [1] * n
        for i in range(2,n+1):
            tmp[i] = l[i-1] + tmp[i-1] + 1
            if floor != k and tmp[i] >= n:
                break
            if floor == k and tmp[i] >= n:
                sign = True
                print(i)
                break
        if sign:
            break
        floor += 1
        l = tmp

Python解法超时了,但是一样的解法用C就不超时 emmmmm

发表于 2019-08-19 16:50:52 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n,k,cnt=0;
    cin>>n>>k;
    int dp[k+1];
    memset(dp, 0, sizeof(dp));
    while(true){
        cnt++;
        for(int i=k;i>0;i--){
            dp[i] = dp[i] + dp[i-1] + 1;
            if(dp[i]>=n){
                cout<<cnt<<endl;
                return 0;
            }
        }
    }
    return 0;
}

发表于 2020-04-18 00:46:07 回复(3)
//一开始不太理解为什么转换问题后:k个棋子扔M次,最多能确定的层数,递归是这样的:dp[k][m] = dp[k - 1][m - 1] + dp[k][m - 1] + 1 

//考虑了很久,终于考虑明白了,来看例子3就懂了,当有k个棋子,扔m次的最优能确定的层数,可以知道在求dp[k][m]的时候,第一步的最优的算法已经确定了,就是例子的算法,
//你要求解的就是往上走能到达的最多层数,往下走能达到的最多层数。比如例子三,已经确定了第一步的最优算法了,已知了k= 2, m = 14, 第一步是从14层扔的,那么往下走
//最多就是dp[k - 1][m - 1];一直往上走,最多是dp[k][m -1],直到m=0,结束。所以就确定了最大的距离是相加的结果:dp[k - 1][m - 1] + dp[k][m - 1] + 1


// 打比方说,例子三,最终的路线是14层扔一次,1~13层各扔一次,确定了第14层就是刚摔碎的那一层,但是最优算法告诉我们,
//我们按照这个最优算法,只要总的层数是<=105,就能够确定第14层就是刚摔碎的那一层。


// 递归的含义是针对最优算法的最大层数,而不是某一次试验所确定的最大层数。
发表于 2021-08-03 19:50:45 回复(0)

问题信息

上传者:小小
难度:
3条回答 3046浏览

热门推荐

通过挑战的用户

查看代码