LuoguP1880[NOI1995]石子合并

Description:

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分。
区间DP,状态转移方程dp[l][r] = max(dp[l][r],dp[l][k] + dp[k+1][r] + sum[r] - sum[l-1]) 其中,k为区间中间点,sum[] 维护前缀和
区间动归状态转移方程及一般动规过程:

for len:=1 to n-1 do    //区间长度
  for l:=1 to n-len do     //区间起点
    for k:=l to l+len-1 do     //区间中任意点
      dp[r,l+len]:=max{dp[l,k] + dp[k+1,l+len] + a[l,k] + a[k+1,i+len]

区间长度len必须要放到第一层循环,来保证方程中状态dp[l,k]、dp[k+1,l+k]值在dp[l,l+k]之前就已计算出来。
一开始不明白为什么要用堆数作为阶段,写了个类似于Floyd的DP

for(int k = l;k < r;++k)
	{
		for(int l = 1;l < n << 1;++l){
			for(int r = l + 1;r <= n << 1;++r){
				dp1[l][r] = min(dp1[l][r],dp1[l][k] + dp1[k + 1][r] + sum[r] - sum[l-1]);
				dp2[l][r] = max(dp2[l][r],dp1[l][k] + dp2[k + 1][r] + sum[r] - sum[l-1]);
			}
		}		
	}

但是编译没通过,因为k循环不好赋值,难以实现,因此还是枚举区间长度好了。
https://www.cnblogs.com/Zforw/p/10617652.html

Code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
#define N 110
#define ll long long
using namespace std;
ll dp2[N << 1][N << 1],dp1[N << 1][N << 1],n,ans1,ans2;
ll sum[N << 1],a[N << 1];
int main() {
    scanf("%lld",&n);
    memset(dp1,0x3f,sizeof(dp1));
    for(int i = 1; i <= n; i++) {
        scanf("%lld",&a[i]);
        a[i + n] = a[i];
    }
    for(int i = 1;i <= n << 1;++i){
        sum[i] = sum[i-1] + a[i];
        dp2[i][i] = dp1[i][i] = 0;
    }
    for(int i = 1; i <= n;++i)
        dp2[i][i] = dp1[i][i] = 0;
    // 以合并的堆数为阶段
    for(int len = 2; len <= n;++len) {
        for(int l = 1; l <= (n << 1 | 1) - len;++l) {
            int r = len + l - 1;
            for(int k = l; k < r;++k) {
                dp1[l][r] = min(dp1[l][r],dp1[l][k] + dp1[k + 1][r] + sum[r] - sum[l-1]);
                dp2[l][r] = max(dp2[l][r],dp2[l][k] + dp2[k + 1][r] + sum[r] - sum[l-1]);
            }
        }
    }
    ans1 = 0x3f3f3f3f;
    for(int i = 1;i <= n;++i) ans1 = min(ans1,dp1[i][i + n - 1]);
    for(int i = 1;i <= n;++i) ans2 = max(ans2,dp2[i][i + n - 1]);
    printf("%lld\n%lld",ans1,ans2);
    return 0;
}
posted @ 2019-03-27 20:51  Zforw  阅读(45)  评论(0编辑  收藏  举报