石子归并(dp + 四边形不等式优化)

题目

N堆石子摆成一个环。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的代价。计算将N堆石子合并成一堆的最小代价。

例如: 1 2 3 4,有不少合并方法
1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)
1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)
1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)

括号里面为总代价可以看出,第一种方法的代价最低,现在给出n堆石子的数量,计算最小合并代价。
Input
第1行:N(2 <= N <= 1000)
第2 - N + 1:N堆石子的数量(1 <= Aii <= 10000)
Output
输出最小合并代价
Sample Input
4
1
2
3
4
Sample Output
19

优化讲解:点击这里

这道题,用之前的老方法是会超时的,需要一个“四边形不等式优化”方法,方法大概是看懂了,但是具体的推理过程我没有看懂,觉得看着挺复杂的,本来想着我这样的想法和做法应该是很不好的,但是我们打ACM的又不是搞数学推理研究的,非太大的精力去吧那些很复杂的数学推理弄明白,没有太大的意思。

代码如下:

#include 
#include 
#include 
#include 
#define LL long long
using namespace std;

int s[2010][2010];//表示->j之间的最优分割点的位置
void demo(int dp[][2010], int *arr, int n)
{
    for (int i = 1; i <= 2*n-1; i++)
    {
        s[i][i] = i;
        for (int j = 1; j <= 2*n-1; j++)
            dp[i][j] = (i == j)? 0 : 1e9;
    }
    for (int i = 2*n-1; i >= 1; i--)
        for (int j = i+1; j <= 2*n-1; j++)
            for (int k = s[i][j-1]; k <= s[i+1][j]; k++)
            {
                int temp = dp[i][k] + dp[k+1][j] + arr[j] - arr[i-1];
                if (dp[i][j] > temp)
                {
                    dp[i][j] = temp;
                    s[i][j] = k;
                }
            }

}

void get_min_cost(int dp[][2010], int n, int &min_cost)
{
    min_cost = 1e9;
    int index = 1;

    while(n+index-1 <= 2*n-1)
    {
        min_cost = min(min_cost, dp[index][n+index-1]);
        index++;
    }
}

int main()
{
    int n;
    int min_cost = 0;
    int arr[2010];
    static int dp[2010][2010];

    scanf("%d", &n);
    arr[0] = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &arr[i]);
        arr[i+n] = arr[i];
    }

    for (int i = 1; i <= 2*n-1; i++)
        arr[i] += arr[i-1];

    demo(dp, arr, n);
    get_min_cost(dp, n, min_cost);

    printf("%d\n", min_cost);

    return 0;
}

你可能感兴趣的:(动态规划)