区间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;
}

 

posted @ 2020-04-22 12:22  龙雪可可  阅读(108)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************