SDNU 1048.石子合并2(区间dp)
Description
有n堆石子排成一圈,每次选择相邻的两堆石子,将其合并为一堆,记录该次合并的得分为两堆石子个数之和。已知每堆石子的石子个数,求当所有石子合并为一堆时,最小的总得分。
Input
第一行一个整数n(1 <= n <= 200),表示石子堆数; 第二行n个整数a(1 <= a <= 100),表示每堆石子的个数,这些石子首尾相接排成一圈。
Output
一个整数,表示最小总得分。
Sample Input
5 7 6 5 7 100
Sample Output
175
Source
Unknown
#include<bits/stdc++.h> using namespace std; #define ll long long #define eps 1e-9 #define pi acos(-1) const int inf = 0x3f3f3f3f; const int mod = 1e9+7; const int maxn = 1000 + 8; int n, a[maxn], sum[maxn], dp[maxn][maxn], mi; int main() { std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; sum[0] = 0; for(int i = 1; i <= n; i++) { cin >> a[i]; sum[i] += a[i] + sum[i - 1]; } for(int len = 1; len <= n; len++) { for(int i = 1; i <= n; i++) { int en = (i + len) % n == 0 ? n : (i + len) % n; int tmp; if(i + len <= n) tmp = sum[i + len] - sum[i - 1]; else tmp = sum[n] - sum[i - 1] + sum[(i + len) % n]; dp[i][en] = inf; for(int k = 0; k < len; k++) dp[i][en] = min(dp[i][en], dp[i][(i + k) % n == 0 ? n : (i + k) % n] + dp[(i + k + 1) % n == 0 ? n : (i + k + 1) % n][en] + tmp); } } mi = dp[1][n]; for(int i = 2; i <= n; i++) if(mi > dp[i][i - 1]) mi = dp[i][i - 1]; cout << mi <<'\n'; return 0; }