題目
19182 石子合併(基礎版)
時間限制:1000MS 程式碼長度限制:10KB
提交次數:0 透過次數:0
題型: 程式設計題 語言: 不限定
Description
設有 N(N≤300) 堆石子排成一排,其編號為1,2,3,⋯,N。每堆石子有一定的質量 mi(mi≤1000)。
現在要將這N堆石子合併成為一堆。每次只能合併相鄰的兩堆,合併的代價為這兩堆石子的質量之和,合併後與這兩堆石子相鄰的石子將和新堆相鄰。
合併時由於選擇的順序不同,合併的總代價也不相同。試找出一種合理的方法,使總的代價最小,並輸出最小代價。
輸入格式
第一行,一個整數 N。
第二行,N 個整數 mi。
輸出格式
輸出僅一個整數,也就是最小代價。(題目確保答案在int範圍)
輸入樣例
4
2 5 3 1
輸出樣例
22
提示
區間動態規劃。題解可參考 11078 不能移動的石子合併(優先做)
點選檢視程式碼
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define N 301
using namespace std;
int s[N]; // (字首和)s[i]表示前i個整數之和
int dp[N][N]; // dp[i][j]表示將第i個石頭到第j個石頭合併在一起的方案集合中的最小代價
int main()
{
memset(dp, 0x7f, sizeof(dp)); // 給dp每個位置設定最大值,因為後面要用min找最小代價
int n;
cin >> n;
s[0] = 0;
for(int i = 1; i <= n; i++)
{
cin >> s[i];
s[i] += s[i - 1];
dp[i][i] = 0; // 自己和自己不用合併,代價是0
}
for(int len = 2; len <= n; len++) // 合併長度範圍
{
for(int l = 1; l + len - 1 <= n; l++) // 合併集合的左邊界
{
int r = l + len - 1; // 合併集合的右邊界
for(int mid = l; mid < r; mid++) // 將集合拆分成兩部分
{
dp[l][r] = min(dp[l][r], dp[l][mid] + dp[mid + 1][r] + s[r] - s[l - 1]); // 找到最小代價
}
}
}
cout << dp[1][n];
return 0;
}
放自己部落格複習用
轉發自
https://blog.csdn.net/weixin_54218079/article/details/127969565