• 算法提高 合并石子 四边形优化法则


    算法提高 合并石子  
    时间限制:2.0s   内存限制:256.0MB
       
    问题描述
      在一条直线上有n堆石子,每堆有一定的数量,每次可以将两堆相邻的石子合并,合并后放在两堆的中间位置,合并的费用为两堆石子的总数。求把所有石子合并成一堆的最小花费。
    输入格式
      输入第一行包含一个整数n,表示石子的堆数。
      接下来一行,包含n个整数,按顺序给出每堆石子的大小 。
    输出格式
      输出一个整数,表示合并的最小花费。
    样例输入
    5
    1 2 3 4 5
    样例输出
    33
    数据规模和约定
      1<=n<=1000, 每堆石子至少1颗,最多10000颗。

    90分代码,优化之后,重新贴一份:
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXN=1005;
    const int INF=0x3f3f3f3f;
    int dp[MAXN][MAXN];
    int sum[MAXN];
    int main()
    {
        int n;
        int num;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            sum[i]=sum[i-1]+num;
        }
        for(int len=2;len<=n;len++)//从最小的长度开始合并
        {
            for(int i=1;i<=n-len+1;i++)//i为开始的下标
            {
                int j=i+len-1;//结束的下标
                int minvalue=INF;
                for(int k=i;k<j;k++)
                {
                    minvalue=min(minvalue,dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
                }
                dp[i][j]=minvalue;
            }
        }
        printf("%d
    ",dp[1][n]);
        return 0;
    }
    
    

    100分代码(利用四边形优化):


    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXN=1005;
    const int INF=0x3f3f3f3f;
    int dp[MAXN][MAXN],s[MAXN][MAXN];
    int sum[MAXN];
    int main()
    {
        int n;
        int num;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&num);
            sum[i]=sum[i-1]+num;
        }
        for(int i=1;i<=n;i++)
            s[i][i]=i;
        for(int len=2;len<=n;len++)//从最小的长度开始合并
        {
            for(int i=1;i<=n-len+1;i++)//i为开始的下标
            {
                int j=i+len-1;//结束的下标
                int minvalue=INF;
                for(int k=s[i][j-1];k<=s[i+1][j];k++)
                {
                    if(minvalue>dp[i][k]+dp[k+1][j])
                    {
                        s[i][j]=k;
                        minvalue=dp[i][k]+dp[k+1][j];
                    }
                }
                dp[i][j]=minvalue+sum[j]-sum[i-1];
            }
        }
        printf("%d
    ",dp[1][n]);
        return 0;
    }
    


  • 相关阅读:
    QLU Regular Contest 002 题解
    QLU_ACM 2021 专题训练(一)题解 [暴力、排序、贪心、二分]
    QLU ACM-ICPC 2020 Training Contest 11 @2016 ICPC Dalian [Cloned] 题解
    Codeforces Round #696 (Div. 2) AB题解
    Educational Codeforces Round 102 (Rated for Div. 2) ABCD题解
    20210114
    Codeforces Round #169 (Div. 2) CDE题解
    树剖注意要点
    bzoj3631树链剖分
    bzoj1103树状数组水题
  • 原文地址:https://www.cnblogs.com/lemonbiscuit/p/7776016.html
Copyright © 2020-2023  润新知