282. 石子合并
- 状态表示:合并\(l\)到\(r\)这一区间需要的最小代价
- 状态计算:
- 枚举区间长度
- 枚举分割点,将所有状态进行划分
#include <iostream>
using namespace std;
const int N = 310;
int a[N], s[N], dp[N][N];
int main() {
int n; cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
s[i] = s[i - 1] + a[i];
}
// 枚举区间长度
for(int len = 2; len <= n; len++) {
// 确定左右端点
for(int i = 1; i + len - 1 <= n; i++) {
int l = i, r = i + len - 1;
dp[l][r] = 1e9;
// 枚举决策点
for(int k = l; k < r; k++)
dp[l][r] = min (
dp[l][r],
dp[l][k] + dp[k + 1][r] + s[r] - s[l - 1]
);
}
}
cout << dp[1][n];
return 0;
}
环形DP
1068. 环形石子合并
- 利用倍增,将环转换成线性的
#include <iostream>
using namespace std;
const int N = 210, M = N << 1;
int a[N], s[M], h[M];
int dp[N][N], f[N][N];
int main() {
int n; cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
for(int i = 0; i < 2 * n; i++) s[i] = a[i % n] + s[i - 1];
// for(int i = 0; i < 2 * n; i++) cout << s[i] << " ";
// cout << endl;
for(int g = 0; g < n; g++) {
for(int len = 2; len <= n; len++) {
for(int i = g; i + len - 1 < 2 * n; i++) {
int l = i, r = i + len - 1;
dp[l][r] = 1e9, f[l][r] = -2e9;
for(int k = l; k < r; k++) {
dp[l][r] = min(
dp[l][r],
dp[l][k] + dp[k + 1][r] + s[r] - s[l - 1]
);
f[l][r] = max(
f[l][r],
f[l][k] + f[k + 1][r] + s[r] - s[i - 1]
);
// cout << l << " " << r << " " << dp[l][r] << " " << endl;;
}
}
}
}
int mi = 1e9, mx = -1;
for(int i = 0; i < n; i++) {
mi = min(mi, dp[i][i + n - 1]);
mx = max(mx, f[i][i + n - 1]);
}
cout << mi << endl << mx;
return 0;
}
1069. 凸多边形的划分
- 区间DP + 高精度算法
- 状态表示:从顶点\(i\)到\(j\)之间划分成\(N - 2\)个互不相交的三角形的集合
- 状态计算: \(dp[i][j] = min(dp[i][j], dp[i][k] * dp[k][j] + w[i] * w[k] * w[j]\)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 55, M = 100, INF = 1e9;
int n;
LL w[N];
string dp[M][M];
string add(string a, string b) {
if(a.size() < b.size()) return add(b, a);
vector<LL> x, y;
string ans = "";
for(LL i = a.length() - 1; i >= 0; i--) x.push_back(a[i] - '0');
for(LL i = b.length() - 1; i >= 0; i--) y.push_back(b[i] - '0');
LL t = 0;
for(LL i = 0; i < (int)x.size(); i++) {
t += x[i];
if(i < (int)y.size()) t += y[i];
ans += ((t % 10) + '0');
t /= 10;
}
if(t) ans += "1";
reverse(ans.begin(), ans.end());
return ans;
}
string mul(string a, LL b) {
vector<LL> x;
string ans = "";
for(LL i = a.length() - 1; i >= 0; i--) x.push_back(a[i] - '0');
LL t = 0;
for(LL i = 0; i < (int)x.size() || t; i++) {
if(i < (int)x.size()) t += x[i] * b;
ans += ((t % 10) + '0');
t /= 10;
}
while(ans.back() == '0' && ans.size() > 1) ans.pop_back();
reverse(ans.begin(), ans.end());
return ans;
}
string get_min(string x, string y) {
if (x.size() == 0) return y;
if (y.size() == 0) return x;
if (x.size() > y.size()) return y;
else if (x.size() < y.size()) return x;
return x < y ? x : y;
}
int main() {
cin >> n;
for(LL i = 1; i <= n; i++) cin >> w[i];
for(LL len = 3; len <= n; len ++)
for(LL l = 1; l + len - 1 <= n; l++) {
LL r = l + len - 1;
dp[l][r] = "10000000000000000000000000000000";
for(LL k = l + 1; k < r; k++) {
string tmp = "1";
tmp = mul(mul(mul(tmp, w[l]), w[k]), w[r]);
tmp = add(add(tmp, dp[l][k]), dp[k][r]);
dp[l][r] = get_min(dp[l][r], tmp);
}
}
cout << dp[1][n];
return 0;
}
区间DP记录方案
479. 加分二叉树
- 状态表示:中序遍历为i~j的二叉树的得分的最大值
- 以根节点的位置作为集合划分的依据
- 同时记录每颗子树的根
#include <iostream>
#include <cstring>
using namespace std;
const int N = 30;
int w[N], dp[N][N], g[N][N];
void dfs(int x, int y) {
if(x > y) return ;
int k = g[x][y];
cout << k << " ";
dfs(x, k - 1);
dfs(k + 1, y);
}
int main() {
int n; cin >> n;
for(int i = 1; i <= n; i++) cin >> w[i];
for(int len = 1; len <= n; len ++) {
for(int l = 1; len + l - 1 <= n; l++) {
int r = l + len - 1;
// cout << len << " " << l << " " << r << endl;
if(len == 1) {
dp[l][r] = w[l];
g[l][r] = l;
} else {
// 枚举根的位置
for(int k = l; k <= r; k++) {
// k == l, 说明左子树为空
int left = (k == l) ? 1 : dp[l][k - 1];
// 同理,k == r, 说明右子树为空
int right = (k == r) ? 1 : dp[k + 1][r];
if(dp[l][r] < left * right + w[k]) {
dp[l][r] = left * right + w[k];
// 记录当前子树的根节点
g[l][r] = k;
}
}
}
}
}
cout << dp[1][n] << endl;
dfs(1, n);
return 0;
}
原文链接: https://www.cnblogs.com/Hot-machine/p/13348066.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/368791
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!