動態規劃 區間dp 基礎題

scau發表於2024-11-27

題目
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

相關文章