1.
https://www.luogu.com.cn/problem/P1775
题目大意:
\(n\) 堆石子排成 一排 ,编号为 1, 2, 3,..., \(n\)。每堆石子有一定的质量,用一个整数来表述,现要将这 \(n\) 堆石子合并成为一堆,每次只能合并 相邻 的两堆,合并的代价为这两堆的质量之和,合并后这两堆石子相邻的石子将和新堆相邻,找出最合理的方式,使总代价最小,输出最小代价。
思路:
定义 \(f[i][j] 为 i 到 j\) 的石子合并后最小的代价,这个结果是从两堆石子转移过来,我们定义中间节点为 \(k\),容易得到转移方程 \(f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j] + 代价)\),代价 就是整个区间石子质量的和。
时间复杂度 \(O(n^3)\),数据范围为 200,所以可以过。
区间 \(dp\) 一般最外层循环都为长度。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
int n, s[N], dp[N][N];
int main(){
cin >> n;
for (int i = 1; i <= n; i ++ ){
cin >> s[i];
s[i] += s[i - 1];
}
for (int len = 1; len < n; len ++ ){
for (int i = 1; i <= n - len; i ++ ){
int j = i + len;
dp[i][j] = 1e9;
for (int k = i; k < j; k ++ ){
dp[i][j] = min(dp[i][k] + dp[k + 1][j] + s[j] - s[i - 1], dp[i][j]);
}
}
}
cout << dp[1][n] << "\n";
return 0;
}
2.
https://www.luogu.com.cn/problem/P1880
题目大意:
\(n\) 个石子排成一个环,求最小代价和最大代价。
思路:
将环拆成链,按照区间 \(dp\) 操作即可。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 210;
int n, s[N], f[N][N], g[N][N], mx, mn = 1e9;
int main(){
cin >> n;
for (int i = 1; i <= n; i ++ ){
cin >> s[i];
s[i + n] = s[i];
}
for (int i = 1; i <= 2 * n; i ++ )
s[i] += s[i - 1];
for (int len = 1; len < n; len ++ ){
for (int i = 1; i <= 2 * n - len; i ++ ){
int j = i + len;
f[i][j] = 1e9;
g[i][j] = 0;
for (int k = i; k < j; k ++ ){
f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j] + s[j] - s[i - 1]);
}
}
}
for (int i = 1; i <= n; i ++ ){
mn = min(mn, f[i][i + n - 1]);
mx = max(mx, g[i][i + n - 1]);
}
cout << mn << "\n" << mx << "\n";
return 0;
}
3.
https://www.luogu.com.cn/problem/P5569
题目大意:
与 1 一样,数据范围改成 40000
思路:
http://t.zoukankan.com/winter-bamboo-p-11461352.html
代码: