【ACWing】1068. 环形石子合并

题目地址:

https://www.acwing.com/problem/content/1070/

n n n堆石子绕圆形操场排放,现要将石子有序地合并成一堆。规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。请编写一个程序,读入堆数 n n n及每堆的石子数,并进行如下计算:选择一种合并石子的方案,使得做 n − 1 n−1 n1次合并得分总和最大。选择一种合并石子的方案,使得做 n − 1 n−1 n1次合并得分总和最小。

输入格式:
第一行包含整数 n n n,表示共有 n n n堆石子。第二行包含 n n n个整数,分别表示每堆石子的数量。

输出格式:
输出共两行:第一行为合并得分总和最小值,第二行为合并得分总和最大值。

数据范围:
1 ≤ n ≤ 200 1≤n≤200 1n200

思路是动态规划。由于最后一次合并一定是两个石堆合并,这两个石堆中间的”缝隙边“有 n n n种可能,分别是 1 ∼ 2 , 2 ∼ 3 , . . . , ( n − 1 ) ∼ n , n ∼ 1 1\sim 2,2\sim 3,...,(n-1)\sim n, n\sim 1 12,23,...,(n1)n,n1,我们需要枚举全这些可能性。可以用一个技巧,即将数组长度增加 n − 1 n-1 n1,并且令 i > n , a [ i ] = a [ i − n ] i>n,a[i]=a[i-n] i>n,a[i]=a[in],用这个新的石堆数组来求合并花费最值,然后枚举所有长度为 n n n的区间,即得答案。其实这就是变相在枚举最后一次合并的缝隙边。关于非环形石子合并问题,可以参考https://blog.csdn.net/qq_46105170/article/details/113917297。代码如下:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 410;
int n, a[N], s[N];
int f[N][N], g[N][N];

int main() {
    
    
    cin >> n;
    // 复制一遍数组a,并预处理前缀和
    for (int i = 1; i < 2 * n; i++) {
    
    
        if (i <= n) cin >> a[i];
        else a[i] = a[i - n];

        s[i] = s[i - 1] + a[i];
    }

    memset(f, 0x3f, sizeof f);
	
	// r1存最小花费,r2存最大花费
    int r1 = 0x3f3f3f3f, r2 = 0;
    // 枚举区间长度
    for (int l = 1; l <= n; l++)
    	// 枚举左端点
        for (int i = 1; i + l - 1 < 2 * n; i++) {
    
    
        	// 算出右端点
            int j = i + l - 1;
            if (l == 1) {
    
    
                f[i][j] = 0;
                continue;
            }
			
			// 枚举最后一次合并的分割点,最后一次合并是k及其左的石子与第k + 1及其右的石子的合并
            for (int k = i; k < j; k++) {
    
    
                f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
                g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j] + s[j] - s[i - 1]);
            }
			
			// 用所有长度为n的区间的花费来更新答案
            if (l == n) {
    
    
                r1 = min(r1, f[i][j]);
                r2 = max(r2, g[i][j]);
            }
        }

    cout << r1 << endl;
    cout << r2 << endl;

    return 0;
}

时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( n 2 ) O(n^2) O(n2)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/114574475