• (算法)扔棋子


    题目:

    1、有一个100层高的大厦,你手中有两个相同的玻璃围棋子。从这个大厦的某一层及更高的层扔下围棋子就会碎,用你手中的这两个玻璃围棋子,找出一个最优的策略(扔最少的次数),来得知那个临界层面。

    2、如果大厦高度是N层,你有K个棋子,请问最少需要扔几次可以知道得临界层?

    思路:

    1、推导

    这里不推倒,直接给出结论,具体推导参考:http://blog.csdn.net/jiaomeng/article/details/1435226

    首先选择第x层扔第一个棋子q1:

    如果棋子碎了,则在1~x-1之间通过另一个棋子q2来从下到上依次试探哪一层为临界层面;

    如果棋子没碎,则选择在x+(x-1)=2x-1层继续扔棋子q1:

      如果棋子碎了,则在x+1~2x之间通过另一个棋子q2来从下到上依次试探哪一层为临界层面;

      如果棋子没碎,则选择在x+(x-1)+(x-2)=3x-3继续扔棋子q1;

    。。。。。。

    如果棋子一直没碎,那么棋子q1会一直扔到某一层大于或等于100即停止:x+(x-1)+(x-2)+(x-3)+...+2+1>=100,即求x*(x+1)/2的最小值,使之满足>=100,求解得到x=14.

    即:

    先从14层扔(碎了试1-13,需1+13-1+1=14次)
    再从27层扔(碎了试15-26,需2+26-15+1=14次)
    再从39层扔(碎了试28-38,需3+38-28+1=14次)
    再从50层扔(碎了试40-49,需4+49-40+1=14次)
    再从60层扔(碎了试51-59,需5+59-51+1=14次)
    再从69层扔(碎了试61-68,需6+68-61+1=14次)
    再从77层扔(碎了试70-76,需7+76-70+1=14次)
    再从84层扔(碎了试78-83,需8+83-78+1=14次)
    再从90层扔(碎了试85-89,需9+89-85+1=14次)
    再从95层扔(碎了试91-94,需10+94-91+1=14次)
    再从99层扔(碎了试96-98,需11+98-96+1=14次)
    最后从100层扔(根据题意一定会碎,也可以不扔了,需11次)

    最坏情况下扔14次。

    2、动态规划

    假设dp[i][j]表示有i层,j个棋子时得到临界层,需要的最少次数。

    初始状态:

    当i=1,即只有1层,dp[1][j]=1;(j>0)

    当j=1,只有1个棋子,dp[i][1]=i;(i>0)

    状态转移方程:

    dp[i][j]=min(max(dp[k-1][j-1],dp[i-k][j])+1)  (0<k<i)

    解释:当选择在第k层扔棋子时,此时有两种情况,考虑的最坏情况,因此选择其大者。

    棋子碎了,则棋子数减1,并在1~k-1层试探,此时次数为dp[k-1][j-1]+1;

    棋子未碎,则棋子数不变,在k+1~j层试探,此时次数为dp[j-k][j]+1;

    代码:

    route[i][j]表示当有i层j个棋子的下一步选择哪一层扔棋子,通过route可以记录每次扔棋子的楼层。

    参考:http://blog.csdn.net/taylor_tao/article/details/7084467?reload

    #include <iostream>
    #include <vector>
    #include <stdlib.h>
    
    using namespace std;
    
    #define LAYERS 101
    #define CUPS 3
    
    int main()
    {
        vector<vector<int> > dp(LAYERS,vector<int>(CUPS));
        vector<vector<int> > route(LAYERS,vector<int>(CUPS));
    
        for(int i=1;i<LAYERS;i++){
    //      dp[i][0]=0;
            dp[i][1]=i;
        }
    
        for(int i=1;i<CUPS;i++){
    //      dp[0][i]=0;
            dp[1][i]=1;
            route[1][i]=0;
        }
    
        for(int j=2;j<CUPS;j++){
            for(int i=2;i<LAYERS;i++){
                dp[i][j]=i;
                route[i][j]=0;
                for(int k=1;k<i;k++){
                    int mini=max(dp[k-1][j-1],dp[i-k][j])+1;
                    route[i][j]=mini<=dp[i][j]?k:route[i][j];
                    dp[i][j]=mini<dp[i][j]?mini:dp[i][j];
                }
            }
        }
        cout << dp[LAYERS-1][CUPS-1] <<endl;
        return 0;
    }
  • 相关阅读:
    java 单链表 练习
    大问题-简明哲学导论
    git的常见错误
    python在Ubuntu添加模块搜索路径
    前端
    TCP/IP图解
    调试
    Design program
    算法
    面向对象-聚集,程序比较发现
  • 原文地址:https://www.cnblogs.com/AndyJee/p/4846566.html
Copyright © 2020-2023  润新知