先看题目:https://ac.nowcoder.com/acm/problem/50493
题目描述:
与石子合并1的规则相同,只不过所有石子现在围成了一个环形。
解题思路:
处理环有两种方法,一种是取模,另一种是序列加倍。
序列加倍就是把‘1234’变成'12341234'使循环的完全可以用链的方法解决了。
别忘了dp1[n+1][n+1]...dp[2n][2n]也都要初始化为0 !!
代码(序列加倍)(推荐):

#include<bits/stdc++.h>
using namespace std;
int a[500];
int sum[500];
int dp1[500][500];
int dp2[500][500];
int main()
{
    int n;
    scanf("%d",&n);
    memset(dp1, 0x7f, sizeof(dp1));
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        sum[i] = sum[i-1]+a[i];
        dp1[i][i] = 0;
    }
    for(int i = n+1; i <= 2*n; i++) {
        a[i] = a[i-n];
        dp1[i][i] = 0;
        sum[i] = sum[i-1]+a[i];
    }
    for(int l = 2; l <= n; l++) {
        for(int i = 1; i <= 2*n; i++) {
            int j = i+l-1;
            if(j > 2*n) break;
            for(int k = i; k < j; k++) {
                dp1[i][j] = min(dp1[i][j], dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]);
                dp2[i][j] = max(dp2[i][j], dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);
            }
        }
    }
    int ans1 = 0x3f3f3f3f;
    int ans2 = 0;
    for(int i = 1; i <= n; i++) {
        ans1 = min(ans1, dp1[i][i+n-1]);
        ans2 = max(ans2, dp2[i][i+n-1]);
    }
    printf("%d\n",ans1);
    printf("%d\n",ans2);
}

取模方法最好结合着序列加倍一起思考。
首先要注意序号从0开始,这样的话n%n == 0, n-1%n == n-1,才能形成循环,序号从1开始就不行了。
在之前石子合并1中,在for循环中有这样一个判断

if(j > n) break;

现在是一个环,因此这个就不用加了,比如n==4, 循环至i=3,j=5的时候dp[3][5 % n]就是 dp[3][1], 而dp[1][3]与dp[3][1]所包含的区间是不同的。 (不理解的话再画个表格模拟一遍样例)
还有就是要注意这个求sum并不可以使用前缀和,需要特别写一个getsum函数对取余特别考虑
最后需要遍历一遍所有的长度为n的dp
代码(取模):

#include<bits/stdc++.h>
using namespace std;
int sum[250];
int a[250];
int dp1[250][250];
int dp2[250][250];
int n;
int getsum(int s, int t)
{
    int ans = 0;
    if(t >= n) {
        ans += sum[n-1]-sum[s-1];
        ans += sum[t % n];
    }
    else {
        ans += sum[t]-sum[s-1];
    }
    return ans;
}
int main()
{
    scanf("%d",&n);
    memset(dp1, 0x7f, sizeof(dp1));
    for(int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
    }
    sum[0] = a[0];
    for(int i = 1; i < n; i++) {
        sum[i] = sum[i-1]+a[i];
    }
    for(int i = 0; i < n; i++) {
        dp1[i][i] = 0;
    }
    for(int l = 2; l <= n; l++) {
        for(int i = 0; i < n; i++) {
            int j = i+l-1;
            for(int k = i; k < j; k++) {
                dp1[i][j % n] = min(dp1[i][j % n], dp1[i][k % n]+dp1[(k+1) % n][j % n]+getsum(i, j));
                dp2[i][j % n] = max(dp2[i][j % n], dp2[i][k % n]+dp2[(k+1) % n][j % n]+getsum(i, j));
            }
        }
    }
    int ans1 = 0x3f3f3f3f;
    int ans2 = 0;
    for(int i = 0; i <n; i++) {
        ans1 = min(ans1, dp1[i][(i+n-1) % n]);
        ans2 = max(ans2, dp2[i][(i+n-1) % n]);
    }
    printf("%d\n",ans1);
    printf("%d\n",ans2);
}