[Algo] 区间dp
1. 让字符串成为回文串的最少插入次数
// 1. 让字符串成为回文串的最少插入次数
// https://leetcode.cn/problems/minimum-insertion-steps-to-make-a-string-palindrome/description/
int minInsertions(string s) {
int n = s.length();
vector<vector<int>> dp(n, vector<int>(n));
for (int l = 0; l < n - 1; l++) dp[l][l + 1] = s[l] == s[l + 1] ? 0 : 1;
for (int l = n - 3; l >= 0; l--)
for (int r = l + 2; r <= n - 1; r++)
dp[l][r] = s[l] == s[r] ? dp[l + 1][r - 1] : min(dp[l + 1][r], dp[l][r - 1]) + 1;
return dp[0][n - 1];
}
2. 预测赢家
// 2. 预测赢家
// https://leetcode.cn/problems/predict-the-winner/
int maxScore(vector<int>& nums)
{
int n = nums.size();
vector<vector<int>> dp(n, vector<int>(n));
for (int l = 0; l <= n - 1; l++) dp[l][l] = nums[l];
for (int l = 0; l <= n - 2; l++) dp[l][l + 1] = max(nums[l], nums[l + 1]);
for (int l = n - 3; l >= 0; l--)
for (int r = l + 2; r <= n - 1; r++)
{
int p1 = nums[l] + min(dp[l + 2][r], dp[l + 1][r - 1]);
int p2 = nums[r] + min(dp[l + 1][r - 1], dp[l][r - 2]);
dp[l][r] = max(p1, p2);
}
return dp[0][n - 1];
}
bool predictTheWinner(vector<int>& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
int first = maxScore(nums);
int second = sum - first;
return first >= second;
}
3. 多边形三角剖分的最低得分
// 3. 多边形三角剖分的最低得分
// https://leetcode.cn/problems/minimum-score-triangulation-of-polygon/description/
int minScoreTriangulation(vector<int>& values) {
int n = values.size();
vector<vector<int>> dp(n, vector<int>(n));
for (int l = n - 3; l >= 0; l--)
for (int r = l + 2; r <= n - 1; r++)
{
dp[l][r] = INT32_MAX;
for (int m = l + 1; m < r; m++)
dp[l][r] = min(dp[l][r], dp[l][m] + dp[m][r] + values[l] * values[m] * values[r]);
}
return dp[0][n - 1];
}
4. 切棍子的最小成本
// 4. 切棍子的最小成本
// https://leetcode.cn/problems/minimum-cost-to-cut-a-stick/
int minCost(int n, vector<int>& cuts) {
sort(cuts.begin(), cuts.end());
int m = cuts.size();
vector<int> arr(m + 2);
for (int i = 0; i < m; i++) arr[i + 1] = cuts[i];
arr[m + 1] = n;
// [l...r]第一次切棍子的代价为arr[r + 1] - arr[l - 1]
vector<vector<int>> dp(m + 2, vector<int>(m + 2));
for (int l = 1; l <= m; l++) dp[l][l] = arr[l + 1] - arr[l - 1];
for (int l = m - 1; l >= 1; l--)
for (int r = l + 1; r <= m; r++)
{
dp[l][r] = INT32_MAX;
for (int k = l; k <= r; k++)
dp[l][r] = min(dp[l][r], dp[l][k - 1] + dp[k + 1][r]);
dp[l][r] += arr[r + 1] - arr[l - 1];
}
return dp[1][m];
}
5. 戳气球
// 5. 戳气球
// https://leetcode.cn/problems/burst-balloons/
int maxCoins(vector<int>& nums) {
int n = nums.size();
vector<int> arr(n + 2);
for (int i = 0; i < n; i++) arr[i + 1] = nums[i];
arr[0] = 1;
arr[n + 1] = 1;
vector<vector<int>> dp(n + 2, vector<int>(n + 2));
for (int l = 1; l <= n; l++) dp[l][l] = arr[l - 1] * arr[l] * arr[l + 1];
for (int l = n - 1; l >= 1; l--)
for (int r = l + 1; r <= n; r++)
{
dp[l][r] = INT32_MIN;
for (int k = l; k <= r; k++)
dp[l][r] = max(dp[l][r], dp[l][k - 1] + dp[k + 1][r] + arr[l - 1] * arr[k] * arr[r + 1]);
}
return dp[1][n];
}
6. 布尔运算
// 6. 布尔运算
// https://leetcode.cn/problems/boolean-evaluation-lcci/
struct CountStruct
{
int cntTrue = 0;
int cntFalse = 0;
};
int countEval(string s, int result) {
int n = s.length();
vector<vector<CountStruct>> dp(n, vector<CountStruct>(n));
for (int l = 0; l < n; l += 2)
{
dp[l][l].cntTrue = s[l] == '0' ? 0 : 1;
dp[l][l].cntFalse = s[l] == '0' ? 1 : 0;
}
for (int l = n - 1; l >= 0; l -= 2)
for (int r = l + 2; r <= n - 1; r += 2)
{
int sumTrue = 0, sumFalse = 0;
for (int k = l + 1; k < r; k += 2)
{
CountStruct tmp = dp[l][k - 1];
int lTrue = tmp.cntTrue, lFalse = tmp.cntFalse;
tmp = dp[k + 1][r];
int rTrue = tmp.cntTrue, rFalse = tmp.cntFalse;
if (s[k] == '&')
{
sumTrue += lTrue * rTrue;
sumFalse += lFalse * rFalse + lTrue * rFalse + lFalse * rTrue;
}
else if (s[k] == '|')
{
sumTrue += lTrue * rTrue + lTrue * rFalse + lFalse * rTrue;
sumFalse += lFalse * rFalse;
}
else
{
sumTrue += lTrue * rFalse + lFalse * rTrue;
sumFalse += lTrue * rTrue + lFalse * rFalse;
}
}
dp[l][r].cntTrue = sumTrue;
dp[l][r].cntFalse = sumFalse;
}
return result == 0 ? dp[0][n - 1].cntFalse : dp[0][n - 1].cntTrue;
}