环形石子合并

环形石子合并

n 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。

规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。

请编写一个程序,读入堆数 n 及每堆的石子数,并进行如下计算:

  • 选择一种合并石子的方案,使得做 n1 次合并得分总和最大。
  • 选择一种合并石子的方案,使得做 n1 次合并得分总和最小。

输入格式

第一行包含整数 n,表示共有 n 堆石子。

第二行包含 n 个整数,分别表示每堆石子的数量。

输出格式

输出共两行:

第一行为合并得分总和最小值,

第二行为合并得分总和最大值。

数据范围

1n200

输入样例:

4
4 5 9 4

输出样例:

43
54

 

解题思路

  这题与石子合并差不多一样,只是这题变成了环,需要破环成链。

  比如说有4堆石子,那么除了将 1 2 3 4 合并成一堆石子这种合并方式外,还可以是 2 3 4 1 , 3 4 1 2 , 4 1 2 3 。为了能把环变成区间来求解,就需要破环成链。一个朴素的想法是枚举每一个缺口(因为有n堆石子,因此需要合并n1次,每次合并意味着在两个不连通的点之间连一条线,n个点最后有n1条边,因此存在一个缺口,拉开就成一条链了),此时就得到一个区间,可以做区间dp。但这种做法的时间复杂度为O(n4)

  一共有n种缺口,意味着有n种不同的链。问题的本质是求n个长度为n的链的区间dp。因此可以在长度为n的区间的后面再接一个长度为n的区间,这样区间的长度就变成的2nn个长度为n的链都在这个长度为2n的区间上。

  因此可以在这个长度为2n的链上做区间dp,时间复杂度就变成O(n3)

  AC代码如下:

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 410;
 5 
 6 int s[N];
 7 int f[N][N], g[N][N];
 8 
 9 int main() {
10     int n;
11     scanf("%d", &n);
12     for (int i = 1; i <= n; i++) {
13         scanf("%d", s + i);
14         s[i + n] = s[i];    // 扩展为2倍的长度
15     }
16     for (int i = 1; i <= n << 1; i++) {
17         s[i] += s[i - 1];   // 求前缀和
18     }
19     
20     memset(f, 0x3f, sizeof(f));
21     memset(g, -0x3f, sizeof(g));
22     for (int len = 1; len <= n; len++) {
23         for (int i = 1; i + len - 1 <= n << 1; i++) {
24             int j = i + len - 1;
25             if (len == 1) {
26                 f[i][j] = g[i][j] = 0;
27             }
28             else {
29                 for (int k = i; k < j; k++) {
30                     f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
31                     g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j] + s[j] - s[i - 1]);
32                 }
33             }
34         }
35     }
36     
37     int minv = 2e9, maxv = -2e9;
38     for (int i = 1; i <= n; i++) {  // 枚举所有长度为n的区间,一共有n个
39         minv = min(minv, f[i][i + n - 1]);
40         maxv = max(maxv, g[i][i + n - 1]);
41     }
42     printf("%d\n%d", minv, maxv);
43     
44     return 0;
45 }
复制代码

 

参考资料

  AcWing 1068. 环形石子合并(算法提高课):https://www.acwing.com/video/407/

posted @   onlyblues  阅读(204)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示