C++---interval DP---merging of ring stones (one algorithm per day 2023.4.24)

Note:
This question is an extended question of "interval dp-pebble merging" . The idea of ​​dp is exactly the same, so I won't go into details. You can read that article. This question mainly talks about how to deal with rings.

Topic:
Arrange n piles of stones around the circular playground, and now the stones must be combined into a pile in an orderly manner.
It is stipulated that only two adjacent piles can be selected to merge into a new pile each time, and the number of stones in the new pile is recorded as the score of the merger.

Please write a program to read in the number n of piles and the number of stones in each pile, and perform the following calculation:

  • Choose a scheme for merging stones so that the sum of n−1 merging scores is the largest.
  • Choose a scheme for merging stones so that the sum of n−1 merging scores is the smallest.

Input Format
The first line contains an integer n, indicating that there are n piles of stones.
The second line contains n integers, which respectively represent the number of stones in each pile.

Output Format
There are two lines of output:
the first line is the minimum value of the sum of combined scores, and
the second line is the maximum value of the sum of combined scores.

Data range
1≤n≤200

输入:
4
1 3 5 2
输出:
22
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 410, INF = 0x3f3f3f;      //N开两倍
int n, m, s[N], w[N];        //s存储前缀和,w存储原始值
int f[N][N], g[N][N];    //f存储max,g存储min

int main() {
    
    
    cin >> n;
    for (int i = 1; i<=n; i++) {
    
            //读入数组,并将数组复制一遍接到尾部,比如123,变为123123
        cin >> m;
        w[i] = w[i+n] = m;
    }

    //前缀和处理
    for (int i = 1; i <= n*2; i++) s[i] = s[i-1] + w[i];

    //dp(和基础版石子合并完全相同,只不过同时求了max和min)
    memset(f, -INF, sizeof f);  //f求max,所以初始为负无穷
    memset(g, INF, sizeof g);   //同理
    for (int len = 1; len <= n; len++) {
    
                    //枚举
        for (int i = 1; i+len-1 <= (n*2); i++) {
    
    
            int l = i, r = i+len-1;
            if (len == 1) {
    
    
                f[l][r] = g[l][r] = 0; continue;
            }
            for (int k = l; k < r; k++) {
    
    
                f[l][r] = max(f[l][r], f[l][k] + f[k+1][r] + s[r] - s[l-1]);
                g[l][r] = min(g[l][r], g[l][k] + g[k+1][r] + s[r] - s[l-1]);
            }
        }
    }

    //再枚举所有断点的答案
    int maxv = -INF, minv = INF;
    for (int i = 1; i<=n; i++) {
    
    
        maxv = max(maxv, f[i][i+n-1]);
        minv = min(minv, g[i][i+n-1]);
    }
    cout << minv << endl << maxv << endl;

    return 0;
}

Idea:
Dealing with rings is actually very simple. Let’s take an example. For example, our current array is 1 to 8:
Please add a picture description
each edge represents a merge, and there will be n-1 merges in the end, and there is a gap.
At the same time, we can find out where the gap is The position of , represents a kind of merging plan that exists,
then enumerates all the gaps, that is, calculates all the plans.

But according to the conventional enumeration, it is definitely not possible, because the time complexity
of merging the stones is already high, and enumerating n gaps, that is, it will definitely time out, then you need to use ring optimization, that is , copy the chain once The part is connected at the end, and the chain can be dp:n^3
n^4

Please add a picture description

If it is helpful, please give a free like~ Someone watching is the motivation to support me to write down!

Disclaimer:
The source of the algorithm idea is Mr. Y. For details, please refer to https://www.acwing.com/
This article is only used for learning records and exchanges

Guess you like

Origin blog.csdn.net/SRestia/article/details/130338123