(算法)扔棋子

题目:

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;
}
posted @ 2015-09-29 16:00  AndyJee  阅读(864)  评论(0编辑  收藏  举报