先看题目: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); }