2个鸡蛋100层楼--动态规划

原题:两个软硬程度一样但未知的鸡蛋,它们有可能都在一楼就摔碎,也可能从一百层楼摔下来没事。有座100层的建筑,要你用这两个鸡蛋确定哪一层是鸡蛋可以安全落下的最高位置。可以摔碎两个鸡蛋。在最坏的情况下最少需要几次测试,才能得到摔碎鸡蛋的楼层?
这个题目的解答网上的答案有很多,本文就不细述了,本文主要在于n层楼,a个鸡蛋在最坏情况下的最少测试次数。

TestNum[floorNum][eggNum]表示floorNum层楼,eggNum个鸡蛋时,最坏情况下的测试次数。
动态规划算法通过将原问题分解为子问题,则:

TestNum[floorNum][eggNum]=min{ max(TestNum[floorNum-i][eggNum]+1, TestNum[i-1][eggNum-1]+1) },
其中i=1,2,...,floorNum
显然
TestNum[k][1]=k,0<=k<=eggNum;
TestNum[0][1...eggNum]=0;

解释如下:
首先在第i层扔鸡蛋,若没有破,则剩余测试次数为 :

TestNum[floorNum-i][eggNum];

若鸡蛋破了,则剩余测试次数为

TestNum[i-1][eggNum-1]

故可以据此写出解决该问题的动态规划算法的程序。

1. 带备忘的自顶向下法

int Memorized_MinTestCount(int floorNum, int eggNum)
{
    int **TestNum = new int *[floorNum + 1];
    for (int i = 0; i < floorNum + 1; i++)
    {
        TestNum[i] = new int[eggNum + 1];
    }
    for (int i = 0; i < floorNum + 1; i++)
    {
        for (int j = 0; j < eggNum + 1; j++)
        {
            TestNum[i][j] = 0xFFFFFFFF;
        }
    }

    return  Memorized_Up_Bottom_MinTestCount(TestNum, floorNum, eggNum);
}

int Memorized_Up_Bottom_MinTestCount(int **pNum, int floorNum, int eggNum)
{
    if (pNum[floorNum][eggNum] >= 0)
    {
        return pNum[floorNum][eggNum];
    }
    int minNum = 0xFFFFFFFF;
    if (eggNum == 1)
    {
        minNum = floorNum;
    }
    else if (floorNum == 0)
    {
        minNum = 0;
    }
    else
    {
        for (int k = 1; k <= floorNum; k++)
        {
            if (k == 1)
            {
                minNum = max(Memorized_Up_Bottom_MinTestCount(pNum, floorNum - k, eggNum) + 1, Memorized_Up_Bottom_MinTestCount(pNum, k - 1, eggNum - 1) + 1);
            }
            else
            {
                minNum = min(max(Memorized_Up_Bottom_MinTestCount(pNum, floorNum - k, eggNum) + 1, Memorized_Up_Bottom_MinTestCount(pNum, k - 1, eggNum - 1) + 1), minNum);
            }       
        }
    }   
    pNum[floorNum][eggNum] = minNum;
    return pNum[floorNum][eggNum];
}

2. 自底向上法

int Bottom_Up_MinTestCount(int floorNum, int eggNum)
{
    //分配存储空间
    int **TestNum = new int *[floorNum + 1];
    for (int i = 0; i < floorNum + 1; i++)
    {
        TestNum[i] = new int[eggNum + 1];
    }

    //一个鸡蛋测i层楼最坏情况需要测i次
    for (int i = 0; i < floorNum + 1;i++)
    {
        TestNum[i][1] = i;
    }

    //不管几个鸡蛋,测0层楼最坏情况需要测试0次
    for (int i = 0; i < eggNum + 1;i++)
    {
        TestNum[0][i] = 0;
    }

    if (eggNum==1)//如果只有一个鸡蛋,则测试的次数即为楼层数
    {
        return TestNum[floorNum][1];
    }

    int i, j, k;
    for (i = 2; i < eggNum + 1; i++)
    {
        for (j = 1; j < floorNum + 1; j++)
        {
            int minNum;
            for (k = 1; k <= j; k++)
            {
                if (k == 1)
                {
                    minNum = max(TestNum[j - k][i] + 1, TestNum[k - 1][i - 1] + 1);//给minNum赋初始值
                }
                else
                {
                    minNum = min(max(TestNum[j - k][i] + 1, TestNum[k - 1][i - 1] + 1), minNum);
                }
            }
            TestNum[j][i] = minNum;
        }
    }

    return TestNum[floorNum][eggNum];
}

猜你喜欢

转载自blog.csdn.net/chenlin41204050/article/details/78306650