NUIST OJ 1411 继续合并石子 [DP]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/HZEUHJEJNJ/article/details/79984157

题目

题目描述

在一个圆环上分布着N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数记为得分。

输入描述

每组数据的第1行为正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

输出描述

输出共2行,第1行为最小得分,第2行为最大得分

样例输入

4
4 4 5 9

样例输出

43
54

题目分析

此题和我的上一篇题解十分相近,只需要做出一点微小的改动即可。
因为是环状,所以可以首尾合并了。那么为了简单起见,用空间换写起来方便【大雾】,直接将数据往后扩展了一倍,这样就和上一题一模一样了
唯一需要注意的是:答案不再存储在dp[1][n],因为考虑到首尾合并的问题,实际上是向后滑动了的。因此,最小代价/得分为 min{dp[1][n],dp[2][n+1],……dp[n][2n-1]}。最大代价/得分同理求得。

本题的区间DP

用dp[i][j]表示合并[i,j]区间所需要的最小代价
那么可以方便的得到如下关系
若i=j,则dp[i][j]=0
否则,则dp[i][j]=min{dp[i][k]+dp[k+1][j]}+sum[i][j]
发现:计算dp[i][j]的大区间,需要先计算出dp[i][j]的小区间,所以可以考虑设定一个变量len,从小往大递增,根据此来控制先算小区间,再算大区间
最后,本题要求的是合并所有石子,即[i,j]区间和并的最小代价。
因此,本题答案储存在dp[1][n]内

整体代码与运行结果

/*
ZhangBinjie@Penguin
*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define maxn 105
using namespace std;
int a[maxn*2];
int dp[maxn*2][maxn*2];
int dpm[maxn * 2][maxn * 2];
int sum[maxn*2][maxn*2];
int main() {
    int n;
    int ma, mi;
    while (cin >> n) {
        memset(dp, 0, sizeof(dp));
        memset(dpm, 0, sizeof(dpm));
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
            a[n + i] = a[i];
        }
        for (int i = 1; i <= n; ++i) {
            sum[i][i] = a[i];
            sum[n + i][n + i] = a[i];
            for (int j = i+1; j <= 2*n; ++j) {
                sum[i][j] = sum[i][j - 1] + a[j];
                sum[n + i][n + j] = sum[n + i][n + j - 1] + a[j];
            }
        }
        for (int len = 2; len <= n; ++len) {
            for (int i = 1; i <= 2 * n - len + 1; ++i) {
                dp[i][i + len - 1] = dp[i][i] + dp[i + 1][i + len - 1] + sum[i][i + len - 1];
                dpm[i][i + len - 1] = dpm[i][i] + dpm[i + 1][i + len - 1] + sum[i][i + len - 1];
                for (int k = i + 1; k < i + len - 1; ++k) {
                    dp[i][i + len - 1] = min(dp[i][i + len - 1], dp[i][k] + dp[k + 1][i + len - 1] + sum[i][i + len - 1]);
                    dpm[i][i + len - 1] = max(dpm[i][i + len - 1], dpm[i][k] + dpm[k + 1][i + len - 1] + sum[i][i + len - 1]);
                }
            }
        }
        mi = dp[1][n];
        ma = dpm[1][n];
        for (int i = 2; i < n; ++i) {
            mi = min(mi, dp[i][i + n - 1]);
            ma = max(ma, dpm[i][i + n - 1]);
        }
        cout << ma << " " << mi << endl;
    }
    return 0;
}

结果如下
这里写图片描述

猜你喜欢

转载自blog.csdn.net/HZEUHJEJNJ/article/details/79984157
今日推荐