跳转至

一本通-1274:【例9.18】合并石子(直线排列,小数据)

【题目描述】 在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。

计算出将N堆石子合并成一堆的最小得分。

【输入】 第一行为一个正整数N (2≤N≤100);

以下N行,每行一个正整数,小于10000,分别表示第i堆石子的个数(1≤i≤N)。

【输出】 一个正整数,即最小得分。

【输入样例】 7 13 7 8 16 21 4 18

【输出样例】 269


解法一:朴素动态规划,时间复杂度O(n^3)

#include <bits/stdc++.h>

using namespace std;

const int INF = 0xffffff;

int n;
vector<int> seq(105), preSum(105);
vector<vector<int> > d(105, vector<int>(105, INF)), p(105, vector<int>(105, -1));

int solve()
{
    for (int i = 1; i <= n; ++i) {
        d[i][i] = 0;
        preSum[i] = preSum[i - 1] + seq[i - 1];
    }

    for (int len = 2; len <= n; ++len) { //根据长度划分阶段
        for (int i = 1; i <= n - len + 1; ++i) { //左端点
            int j = i + len - 1; //右端点
            for (int k = i; k < j; ++k) d[i][j] = min(d[i][j], d[i][k] + d[k + 1][j]);
            d[i][j] += preSum[j] - preSum[i - 1];
        }
    }

    return d[1][n];
}

int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> n;
    for (int i = 0; i < n; ++i) cin >> seq[i];

    cout << solve() << endl;

    return 0;
}

解法二:四边形不等式优化,时间复杂度O(n^2)

#include <bits/stdc++.h>

using namespace std;

const int INF = 0xffffff;

int n;
vector<int> seq(105), preSum(105);
vector<vector<int> > d(105, vector<int>(105, INF)), p(105, vector<int>(105, -1));

int solve()
{
    for (int i = 1; i <= n; ++i) { 
        d[i][i] = 0; 
        p[i][i] = i; 
        preSum[i] = preSum[i - 1] + seq[i - 1];
    }

    for (int len = 1; len < n; ++len) { //枚举区间长度
        for (int i = 1; i + len <= n; ++i) { //区间左端点
            int j = i + len; //区间右端点
            for (int k = p[i][j - 1]; k <= p[i + 1][j]; ++k) {
                if (d[i][k] + d[k + 1][j] + preSum[j] - preSum[i - 1] < d[i][j]) {
                    d[i][j] = d[i][k] + d[k + 1][j] + preSum[j] - preSum[i - 1];
                    p[i][j] = k;
                }
            }
        }
    }

    return d[1][n];
}

int main()
{
    std::ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> n;
    for (int i = 0; i < n; ++i) cin >> seq[i];

    cout << solve() << endl;

    return 0;
}