题目
hdu3506
题意:
环状石子合并
思路:
把数组拉长1倍再区间dp
代码
#include <iostream>
#include <algorithm>
#define DEBUG freopen("_in.txt", "r", stdin); freopen("_out1.txt", "w", stdout);
using namespace std;
const int MAXN = 2010;
const int INF = 1e8;
int a[MAXN], dp[MAXN][MAXN], sum[MAXN], u[MAXN][MAXN]; //u[i][j]: 从 i → j 的最优切点k坐标
void solve(int n){
for (int i = 1; i <= n; i++){
scanf("%d", &a[i]);
sum[i] = sum[i-1] + a[i];
u[i][i] = i;
}
for (int i = 1; i <= n; i++){
//拉长1倍
a[i+n] = a[i];
sum[i+n] = sum[i+n-1] + a[i];
u[i+n][i+n] = i+n;
}
n <<= 1;
for (int len = 1; len < n; len++)
for (int i = 1; i <= n - len; i++){
int j = i + len;
dp[i][j] = INF;
for (int k = u[i][j-1]; k <= u[i+1][j]; k++)
if (dp[i][j] > dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]){
dp[i][j] = dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1];
u[i][j] = k; //更新
}
}
int ans = INF;
n >>= 1; //缩回原来长度
for (int i = 1; i <= n; i++)
ans = min(ans, dp[i][i+n-1]);
printf("%d\n", ans);
}
int main(){
int n;
while (~scanf("%d", &n))
solve(n);
return 0;
}