P1880 [NOI1995]石子合并

 

 

 

参考的大佬的博客

求什么设什么,dp[l][r]为l到r堆范围的石子数量的最值

相邻合并为一堆,所以枚举最小值是2

这两堆又是由另外的两堆石子合并,可认为是由dp[l][k]和dp[k + 1][r]

根据k的值将对应范围分为了两部分,然后根据公式会分为更多部分

 

#include <bits/stdc++.h>
using namespace std;
int n,a[210];
int dp1[210][210],dp2[210][210];
int main(){
    //freopen("in","r",stdin);
    ios::sync_with_stdio(0);
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        a[i + n] = a[i];
    }

    for(int i = 1; i <= 2 * n; i++)
        a[i] += a[i - 1];

    //枚举区间长度,最小是2堆开始合并
    for(int len = 2; len <= n; len++){
        //枚举起点
        for(int l = 1; l + len - 1 <  2 * n; l++){
            int r = l + len - 1;//终点
            dp1[l][r] = 99999;
            dp2[l][r] = -99999;
            //不能等于,等于的话就是一堆了
            for(int k = l; k < r; k++){
                dp1[l][r] = min(dp1[l][r],dp1[l][k] + dp1[k + 1][r] + a[r] - a[l - 1]);
                dp2[l][r] = max(dp2[l][r],dp2[l][k] + dp2[k + 1][r] + a[r] - a[l - 1]);
            }
        }
    }
    int minn = 99999;
    int maxx = -99999;
    for(int i = 1; i <= n; i++){
        minn = min(minn,dp1[i][i + n - 1]);
        maxx = max(maxx,dp2[i][i + n - 1]);
    }
    cout << minn << endl << maxx;
    return 0;
}
View Code

 

posted @ 2020-04-28 21:19  Hazelxcf  阅读(114)  评论(0编辑  收藏  举报