zoukankan      html  css  js  c++  java
  • 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
    %lld",ans1,ans2);
        return 0;
    }
    
    岂能尽如人意,但求无愧我心
  • 相关阅读:
    HDU 1009 FatMouse' Trade
    HDU 2602 (简单的01背包) Bone Collector
    LA 3902 Network
    HDU 4513 吉哥系列故事——完美队形II
    LA 4794 Sharing Chocolate
    POJ (Manacher) Palindrome
    HDU 3294 (Manacher) Girls' research
    HDU 3068 (Manacher) 最长回文
    Tyvj 1085 派对
    Tyvj 1030 乳草的入侵
  • 原文地址:https://www.cnblogs.com/Zforw/p/10610645.html
Copyright © 2011-2022 走看看