2017 icpc beijing J - Pangu and Stones

题意:

给你n堆石头,l,r,每次可以合并区间长度[l,r]的石子,合并代价为石子数目和

问你最后能否合并成一堆 0 : 合并代价

思路:

计算区间石子和的话先求个前缀和方便后面用

dp[i][j][k]——区间[i,j]合并成k堆的花费  dp初始化inf

对于区间长度len 有1 ~ n,可知对于每个len的[i,j]   初始dp[i][j][len] = 0

对于每个len 枚举k:2~len  对于每个k将[i,j]拆成两部分 dp[i][j][k] = min(dp[i][j][k],dp[i][L][1] + dp[L + 1][j][k - 1]);

当k的区间范围属于允许合并成一堆的范畴 dp[i][j][1] = min(dp[i][j][1],dp[i][j][k] + sum[j] - sum[l - 1]);

dp[1][n][1]就是答案

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>

using namespace std;
const int MaxN = 102;
const int inf = 0x3f3f3f3f;

int n,l,r;
int a[MaxN],sum[MaxN];
int dp[MaxN][MaxN][MaxN];

int main()
{
	while(~scanf("%d %d %d",&n,&l,&r)){
		for(int i = 1;i <= n; i++) scanf("%d",&a[i]);
		for(int i = 1;i <= n; i++) sum[i] = sum[i - 1] + a[i];
		for(int i = 1;i <= n; i++){
			for(int j = 1;j <= n; j++){
				for(int k = 1;k <= n; k++){
					dp[i][j][k] = inf;
				}
			}
		}
		for(int len = 1;len <= n; len++){
			for(int i = 1;i + len - 1 <= n; i++){
				int j = i + len - 1;
				dp[i][j][len] = 0;
				for(int k = 2;k <= len; k++){
					for(int L = i;L <= j; L++){
						dp[i][j][k] = min(dp[i][j][k],dp[i][L][1] + dp[L + 1][j][k - 1]);
					}
					if(k <= r && k >= l) dp[i][j][1] = min(dp[i][j][1],dp[i][j][k] + sum[j] - sum[i - 1]);
				}
			}
		}
		if(dp[1][n][1] >= inf) printf("0\n");
		else printf("%d\n",dp[1][n][1]);
	}
}
发布了31 篇原创文章 · 获赞 5 · 访问量 1372

猜你喜欢

转载自blog.csdn.net/qq_43685900/article/details/102520896