(环状区间dp)hdu 3506 Monkey Party

题目
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;
}

猜你喜欢

转载自blog.csdn.net/ymxyld/article/details/113780302