写在代码之前
这三题是书中的最后三题,把它们写在一块是因为三个问题的解法中都有对动态规划解法和对动态规划的四边形不等式优化的解法。问题是在与看了一些动态规划的四边形不等式优化讲解之后还是没有特别理解,在此做个小记录,后面有时间再进一步分析。
丢棋子问题
题目
一座大楼有0~N层,地面算第0层,最高一层为第N层,已知棋子从第0层掉落肯定不会摔碎,从第i层掉落可能摔碎,也可能不会摔碎(1<=i<=N)。给定整数N作为楼层数,再给定整数K作为棋子数,返回如果想找到棋子不会摔碎的最高层数,即使在最差的情况下扔的最少次数,一次只能扔一个棋子。
详细分析参考书籍,根据书上JAVA代码写出C++代码
代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
/*暴力递归,时间复杂度会达到O(N!)*/
int process1(int nLevel, int k)
{
if (nLevel == 0)
return 0;
if (k == 1)
return nLevel;
int Min = INT_MAX;
for (int i = 1; i != nLevel + 1; i++)
{
Min = min(Min, max(process1(i - 1, k - 1), process1(nLevel - i, k)));
}
return Min + 1;
}
int solution1(int nLevel, int k)
{
if (nLevel < 1 || k < 1)
return 0;
return process1(nLevel, k);
}
/*动态规划,对于每个位置枚举时间复杂度为O(N),递归过程中,一共有N×K个位置要枚举,O(N*k)
所以总时间复杂度为O(N^2*K)*/
int solution2(int nLevel, int k)
{
if (nLevel < 1 || k < 1)
return 0;
if (k == 1)
return nLevel;
vector<vector<int>> dp(nLevel + 1, vector<int>(k + 1, 0));
for (int i = 1; i != nLevel + 1; i++)
dp[i][1] = i;
for (int i = 1; i != nLevel + 1; i++)
{
for (int j = 2; j != k + 1; j++)
{
int Min = INT_MAX;
for (int k = 1; k != i + 1; k++)
{
Min = min(Min, max(dp[k - 1][j - 1], dp[i - k][j]));
}
dp[i][j] = Min + 1;
}
}
return dp[nLevel][k];
}
/*动态规划,空间压缩*/
int solution3(int nLevel, int k)
{
if (nLevel < 1 || k < 1)
return 0;
if (k == 1)
return nLevel;
vector<int>preArr(nLevel + 1, 0);
vector<int>curArr(nLevel + 1, 0);
for (int i = 1; i != nLevel + 1; i++)
{
preArr[i] = 0;
curArr[i] = i;
}
for (int i = 1; i != k; i++)
{
vector<int> tmp = preArr;
preArr = curArr;
curArr = tmp;
for (int j = 1; j != nLevel + 1; j++)
{
int Min = INT_MAX;
for (int k = 1; k != j + 1; k++)
Min = min(Min, max(preArr[k - 1], curArr[j - k]));
curArr[j] = Min + 1;
}
}
return curArr[nLevel];