zoukankan      html  css  js  c++  java
  • P1880 [NOI1995]石子合并

    题目描述

    在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

    试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

    输入格式:

    数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

    输出格式:

    输出共2行,第1行为最小得分,第2行为最大得分.

    输入样例#1:

    4
    4 5 9 4
    

    输出样例#1:

    43
    54
    

    设dp[ i ] [ j ]为区间 [ i , j ]内 j - i + 1个 小堆堆成一个大堆的总分的最小/最大值。
    则 dp [ i ] [ j ] =两子区间:dp[i][k]、dp[k+1][j]得分之和加上 两个子区间石子的总和,可以用前缀和求的。

    #include<bits/stdc++.h>
    using namespace std;
    
    char buf[100000],*L=buf,*R=buf;
    #define gc() L==R&&(R=(L=buf)+fread(buf,1,100000,stdin),L==R)?EOF:*L++;
    template<typename T>
    inline void read(T&x) {
        char ch=gc(); x=0;
        while (ch<'0'||ch>'9')ch=gc();
        while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=gc();
    }
    
    int a[220],sum[220],n,dp_min[220][220],dp_max[220][220];
    int main() {
        memset(dp_min,0x3f3f3f3f,sizeof(dp_min));
        memset(dp_max,-0x3f3f3f3f,sizeof(dp_max));
    //    freopen("in.txt","r",stdin);
        read(n);
        for(int i=1; i<=n; ++i) {
            read(a[i]);
            a[n+i]=a[i];//化环为线
        }
        for(int i=1; i<=2*n; ++i) {
            sum[i]=sum[i-1]+a[i];
            dp_min[i][i]=0;//区间内只有一个石子,不能合成
            dp_max[i][i]=0;
        }
        for(int l=2; l<=n; ++l) {// l<=>j-i+1表示长度,长度小可以推出长度大的,故最外层是l
            for(int i=1; i<=2*n+-l; ++i) {
                int j=i+l-1;
                for(int k=i; k<j; ++k) {
                    dp_min[i][j]=min(dp_min[i][j],dp_min[i][k]+dp_min[k+1][j]);//子区间总分的和的最小值
                    dp_max[i][j]=max(dp_max[i][j],dp_max[i][k]+dp_max[k+1][j]);
                }
                dp_min[i][j]+=sum[j]-sum[i-1];//再加上该次合成的得分,即为区间[i,j]的最终得分。
                dp_max[i][j]+=sum[j]-sum[i-1];
            }
        }
        int ans_min=0x3f3f3f3f,ans_max=-0x3f3f3f3f;
        for(int i=1; i<=n; ++i) {
            ans_min=min(ans_min,dp_min[i][n+i-1]);//遍历长度为n的区间,最小值即为答案。
            ans_max=max(ans_max,dp_max[i][n+i-1]);
        }
        cout<<ans_min<<endl<<ans_max;
        return 0;
    }
    
  • 相关阅读:
    简单工厂模式、工厂模式、抽象工厂模式
    直接插入排序
    简单选择排序的陷阱
    面试3 题目二,不修改数组找到重复的数字
    二进制中1的个数(读不懂题目怎么办)
    用两个栈实现队列
    斐波那契数列
    替换空格
    python 实现杨辉三角(依旧遗留问题)
    递归实现二分查找
  • 原文地址:https://www.cnblogs.com/foursmonth/p/14144843.html
Copyright © 2011-2022 走看看