版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38177302/article/details/81388483
题目
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 <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#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;
}