============================================================
又是一道超经典的题目。
对于线性的合并石子问题,dp模型类似于“加括号”那类型的dp题目,设 f(i,j)为 将第i项到第j项合并得到的最优解
关键是,这题目是环形的。环形结构,经常采用双倍长度线性化手段,也就是说,把环形结构看成是长度为环的两倍的线性结构来处理。
环的长度是N,所以题目相当于有一排石子1....N+N,然后就可以用线性的石子合并问题的方法做了。
有个要注意的地方,f(i,j) 总是与 f(N +i, N +j) 相等的,所以可以减少一些不必要的计算。
view
source
print?11 | int getSegmentSum( int i, int j)
{ |
12 | return _sum[j]
- _sum[i] + a[i]; |
18 | if (ans
!= -1) return ans; |
20 | if (i
== j) return ans
= 0; |
21 | if (i
+ 1 == j) return ans
= getSegmentSum(i , j); |
22 | if (i
<= N && j <= N) return ans = dp(N + i,N + j); |
25 | int s = getSegmentSum(i,j); |
26 | for ( int k
= i; k < j; ++k) { |
27 | ans = min(ans, dp(i,k) + dp(k + 1, j) + s); |
36 | if (ans
!= -1) return ans; |
38 | if (i
== j) return ans
= 0; |
39 | if (i
+ 1 == j) return ans
= getSegmentSum(i , j); |
40 | if (i
<= N && j <= N) return ans = dp2(N + i,N + j); |
43 | int s = getSegmentSum(i,j); |
44 | for ( int k
= i; k < j; ++k) { |
45 | ans = max(ans, dp2(i,k) + dp2(k + 1, j) + s); |
55 | for (i
= 1; i <= N; ++i) { |
58 | for (i
= N + 1; i <= N + N; ++i) a[i] = a[i - N]; |
60 | for (i
= 2; i <= N + N; ++i) _sum[i] = a[i] + _sum[i - 1]; |
62 | for (i
= 0; i < 205; ++i) |
63 | for (j
= 0; j < 205; ++j) |
64 | f[i][j]
= g[i][j] = -1; |
72 | for (i
= N + N; i >= 1; --i) |
73 | for (j
= i; j <= N + N; ++j) |
77 | for (i
= 1; i <= N; ++i) { |
78 | ans = min(ans, dp(i,i + N - 1)); |
81 | int ans2
= -2000000000; |
82 | for (i
= 1; i <= N; ++i) { |
83 | ans2 = max(ans2, dp2(i,i + N - 1)); |
85 | printf ( "%d\n%d\n" ,
ans, ans2); |