题目描述
知识点
动态规划之区间DP
我的实现
结果
码前思考
我没有做出来,我是看某位大神的题解才知道是区间DP的。
既然是区间DP那么就是基本套路了:
- 枚举区间的长度;
- 枚举区间的起点和中点;
- 利用已有信息在区间内做文章。(具体做法因题目的不同情况而异,常见的就是对区间进行分割,划分为两个部分,得到子问题,与石子合并问题类似)
代码实现
//一道不那么明显的区间DP问题,区间DP清华好像挺喜欢考的
class Solution {
public:
int maxCoins(vector<int>& nums) {
int len = nums.size();
if(0 == len){
return 0;
}
//为了计算方便,我们将数组右移一个位置,并且右边加一位吧
vector<int> data;
data.push_back(1);
for(int num : nums){
data.push_back(num);
}
data.push_back(1);
//然后初始化数组
vector<vector<int> > dp(len+2,vector<int>(len+2,0)); //注意是len+2
//区间dp,枚举长度
for(int l=1;l<=len;l++){
//区间dp,枚举起点
for(int i=1;i<=len-l+1;i++){
int j=i+l-1;
//在这个区间内再枚举最后选择的那个点
for(int k=i;k<=j;k++){
int cur = dp[i][k-1]+dp[k+1][j]+data[k]*data[i-1]*data[j+1];
dp[i][j] = max(dp[i][j],cur);
}
}
}
return dp[1][len];
}
};
码后反思
- 在数组前后各增加一个元素,方便边界的处理!
- 注意初始化所有的
dp
数组元素值为0,这样当碰到区间边界的时候,下面这段代码也同样生效:
即使是int cur = dp[i][k-1]+dp[k+1][j]+data[k]*data[i-1]*data[j+1];
dp[i][i-1]
也会返回0,这样的处理能够符合语义;
二刷代码
还是使用的区间DP的思想,但是我刚开始很多地方都想错了,果然还是要自己做一遍才知道哪些地方不容易想到。。。
//区间DP问题
class Solution {
public:
int maxCoins(vector<int>& nums) {
int len = nums.size();
if(len==0){
return 0;
}
//开始进行区间DP
vector<vector<int>> dp(len+2,vector<int>(len+2,0));
vector<int> data;
data.push_back(1);
for(int i=0;i<nums.size();i++){
data.push_back(nums[i]);
}
data.push_back(1);
//由于特殊的设置,所以不需要进行初始化
//接下来开始枚举长度
for(int l=1;l<=len;l++){
for(int i=1;i+l-1<=len;i++){
int j = i+l-1;
//printf("i:%d j:%d\n",i,j);
//然后枚举最后一次爆破的点
for(int k=i;k<=j;k++){
int cur = dp[i][k-1]+dp[k+1][j]+data[i-1]*data[k]*data[j+1];
dp[i][j] = max(dp[i][j],cur);
}
}
}
return dp[1][len];
}
};