区间DP——石子合并
状态表示的时候表示的是某一段区间。
动态规划:
1、状态表示:f[i, j] 第i堆到第j堆的区间
1)集合:所有将第i堆和第j堆石子合并成一堆石子的 合并方法的集合
2)min: 所有合并方式代价的最小值
2、状态计算:f[1][n]就是所求的,从第1堆一直合并到第n堆的合并方式的最小值。
最后一定是将两堆合并成一堆,将最后一次合并作为分界线。
PS:所有的减去一个数加上一个数并不会影响最大值和最小值是谁。
[i, k], [k + 1, j]把这最后一步去掉,然后求最小值:f[i, k] + f[k + 1, j] + s[j] - s[i - 1]
然后f[i, j] = Min{f[i, k] + f[k + 1,j] + s[j] - s[i - 1]}, k = i ~ j - 1
时间复杂度:状态两维 O(n^2 * k) = O(n^2 * n) = O(n ^ 3) = 2.7 * 10^7
输入样例:
4
1 3 5 2
输出样例:
22
#include <iostream> #include <algorithm> using namespace std; const int N = 301; int f[N][N], s[N]; int main() { int n; cin>>n; for(int i = 1;i <= n;i++) cin>>s[i]; for(int i = 1;i <= n;i++) s[i] += s[i-1]; for(int len = 2;len <= n;len++) for(int i = 1; i + len - 1 <= n;i++) { int l = i, r = i + len - 1; f[l][r] = 1e9; for(int k = l; k < r; k++) f[l][r] = min(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l - 1]); } cout<<f[1][n]<<endl; }