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

    区间DP模板题

    区间DP模板Code:

    for(int len=2;len<=n;len++)
        {
            for(int i=1;i<=2*n-1;i++)  //区间左端点 
            {
                int j = i + len - 1;  //区间右端点 
                for(int k=i;k<j;k++)  //断点位置 
                {
                    f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
                }
            }
        }

    题目描述

    在一个园形操场的四周摆放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

    这个题的数据存储特点有一点代表性:破环成列,把长度为n的环转换为长度为2n-1的列,再进行一次动归。

    针对于这个题的n很小,我们就可以用它来代表区间长度,这样O(n ^ 3)也能跑过去了

    区间DP的概念就是把一个区间的状态一直分割为它的子区间的状态,一直到这个子区间的状态是显然可求的,最后再将它们综合起来

    举个栗子:

    f[i][j]中我们可以将[i,j]这一个区间划分为[i,k]和[k + 1,j]这两个区间的总状态再进行一次操作

    这个的边界就是[i,k]和[k + 1,j]是显然可求的状态

    这个题要求一个最大值和最小值的问题

    我们可以显而易见地发现最小值一定小于等于最大值

    这样我们可以只建立一个数组先求最小再求最大,节省了两个数组的空间(虽然这不是重点qwq)

    Code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring> 
    using namespace std;
    int f[300][300];  //节省空间 
    int s[300];
    int n,x,ans = 55312725;
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&x);
            s[i] = s[i - 1] + x;
            s[i + n] = s[i];  //把长度开到 2n - 1 
        }
        for(int i=1;i<n;i++)
        s[i + n] += s[n];
        memset(f,10,sizeof(f));  //初始化 
        for(int i=1;i<=2*n-1;i++)
        f[i][i] = 0;
        for(int len=2;len<=n;len++)
        {
            for(int i=1;i<=2*n-1;i++)  //区间左端点 
            {
                int j = i + len - 1;  //区间右端点 
                for(int k=i;k<j;k++)  //断点位置 
                {
                    f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
                }
            }
        }
        for(int i=1;i<=n;i++)
        ans = min(ans,f[i][i + n - 1]);
        printf("%d
    ",ans);  //最小值一定比最大值要小,所以无需更新 
        for(int len=2;len<=n;len++)
        {
            for(int i=1;i<=2*n-1;i++)  //区间左端点 
            {
                int j = i + len - 1;  //区间右端点 
                for(int k=i;k<j;k++)  //断点位置 
                {
                    f[i][j] = max(f[i][j],f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
                }
            }
        }
        for(int i=1;i<=n;i++)
        ans = max(ans,f[i][i + n - 1]);
        printf("%d
    ",ans);
        return 0; 
    }
  • 相关阅读:
    Asp.Net细节性问题技巧精萃
    存储过程(Stored Procedure)及应用
    合并datagrid中内容相同的单元格
    .net 2.0 下发送邮件的方式
    ADO.NET2.0的十大新特性
    sql server 中各个系统表的作用
    DataGrid一些文章的索引,方便查找
    ASP.NET中 WebControls 命名规则
    SQL Server应用程序中的高级SQL注入[转]
    数据操作例子
  • 原文地址:https://www.cnblogs.com/lyp-Bird/p/10731672.html
Copyright © 2011-2022 走看看