zoukankan      html  css  js  c++  java
  • 区间DP——石子合并一家人(C++)

     

    A. 石子合并<一>

    入门版:一线

    内存限制:128 MiB    时间限制:1000 ms    标准输入输出
    题目类型:传统    评测方式:文本比较

    题目描述

    有N堆石子排成一排(n<=100),现要将石子有次序地合并成一堆,规定每次只能选相邻的两堆合并成一堆,并将新的一堆的石子数,记为改次合并的得分,编一程序,由文件读入堆数n及每堆石子数(<=200);

    (1)选择一种合并石子的方案,使得做n-1次合并,得分的总和最少

    (2)选择一种合并石子的方案,使得做n-1次合并,得分的总和最多

    输入格式

    第一行为石子堆数n 第二行为每堆石子数,每两个数之间用一空格分隔。

    输出格式

    从第1行为得分最小第二行是得分最大。

    样例

    样例输入
    4
    4 5 9 4

    样例输出
    44
    54

     首先,本文讲的是DP石子合并,而非贪心合并果子二者的区别就在于此——每次只能选相邻的两堆合并成一堆还是任意合并。

    思路

    设dpmin[i]--[j]表示

    附上代码

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 int n,dpmax[500][500],dpmin[500][500]/*前i-j最优解*/,sum[500][500],read[500],tot;
     6 int main()
     7 {
     8     cin>>n;
     9     for(int i=1;i<=n;i++)
    10     {
    11         cin>>read[i];
    12     }
    13     for(int i=1;i<=n;i++)
    14     {
    15         tot=read[i];
    16         for(int j=i+1;j<=n;j++)
    17         {
    18             tot+=read[j];
    19             sum[i][j]=tot;
    20         }
    21     }
    22     memset(dpmin,0x3f,sizeof(dpmin));
    23     for(int i=1;i<=n;i++)
    24         dpmin[i][i]=0; 
    25     for(int len=1;len<n;len++)
    26     {
    27         for(int i=1;i<=n&&len+1<=n;i++)
    28         {
    29             int j=len+i;
    30             for(int k=i;k<=j;k++)
    31             {
    32                 dpmax[i][j]=max(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]);
    33                 dpmin[i][j]=min(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]);
    34             }
    35             dpmax[i][j]+=sum[i][j];
    36             dpmin[i][j]+=sum[i][j]; 
    37         }
    38     }
    39     cout<<dpmin[1][n]<<endl;
    40     cout<<dpmax[1][n];
    41 }

    B. 石子合并<2>

    进阶版:拆分

    题目描述

    在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

    输入格式

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

    输出格式

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

    样例

    样例输入

    4
    4 4 5 9
    

    样例输出

    43

    54

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 int n,dpmax[1001][1001],dpmin[1001][1001],sum[1001][1001],read[1001],tot,maxi,mini=99999999;
     6 int main()
     7 {
     8     cin>>n;
     9     for(int i=1;i<=n;i++)
    10         cin>>read[i];
    11     for(int i=n+1;i<=2*n-1;i++)
    12         read[i]=read[i-n];
    13     for(int i=1;i<=2*n-1;i++)
    14     {
    15         tot=read[i];
    16         for(int j=i+1;j<=2*n-1;j++)
    17         {
    18             tot+=read[j];
    19             sum[i][j]=tot;
    20         }
    21     }
    22     memset(dpmin,0x3f,sizeof(dpmin));
    23     for(int i=1;i<=2*n-1;i++)
    24         dpmin[i][i]=0; 
    25     for(int len=1;len<n;len++)
    26     {
    27         for(int i=1;i<=2*n-1&&len+i<=2*n-1;i++)
    28         {
    29             int j=len+i;
    30             for(int k=i;k<=j;k++)
    31             {
    32                 dpmax[i][j]=max(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]);
    33                 dpmin[i][j]=min(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]);
    34             }
    35             dpmax[i][j]+=sum[i][j];
    36             dpmin[i][j]+=sum[i][j];
    37         }
    38     }
    39     for(int i=1;i<=n;i++)
    40     {
    41         maxi=max(maxi,dpmax[i][i+n-1]);
    42         mini=min(mini,dpmin[i][i+n-1]);
    43     }
    44     cout<<mini<<endl<<maxi;
    45 }

    C. 石子合并<3>

    优化版:数学支持

    题目描述

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

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

    输入格式

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

    输出格式

    输出共1行,最大得分

    样例

    样例输入

    4
    4 4 5 9
    

    样例输出

    54


     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 unsigned int n,dpmax[4011][4011],sum[4011][4011],read[4011],tot,maxi,mini=99999999,k;
     6 int main()
     7 {
     8     cin>>n;
     9     for(int i=1;i<=n;i++)
    10         cin>>read[i];
    11     for(int i=n+1;i<=2*n-1;i++)
    12         read[i]=read[i-n];
    13     for(int i=1;i<=2*n-1;i++)
    14     {
    15         tot=read[i];
    16         for(int j=i+1;j<=2*n-1;j++)
    17         {
    18             tot+=read[j];
    19             sum[i][j]=tot;
    20         }
    21     }
    22     for(int len=1;len<n;len++)
    23     {
    24         for(int i=1;i<=2*n-1&&len+i<=2*n-1;i++)
    25         {
    26             int j=len+i;
    27             dpmax[i][j]=max(dpmax[i][j-1],dpmax[i+1][j]);
    28             dpmax[i][j]+=sum[i][j];
    29         }
    30     }
    31     for(int i=1;i<=n;i++)
    32         maxi=max(maxi,dpmax[i][i+n-1]);
    33     cout<<maxi;
    34 }
     
  • 相关阅读:
    Java学习笔记(一)语法
    【转,整理】C# 非托管代码
    HTML5学习笔记(七)WebSocket
    HTML5学习笔记(七)HTML5 服务器发送事件(Server-Sent Events)
    MySQL修改表格内容3
    MySQL修改表格内容2
    MySQL修改表格内容
    MySQL创建表格
    if-else if-else;多选择结构
    面向对象和面向过程的初步概念
  • 原文地址:https://www.cnblogs.com/lihaolin/p/11270310.html
Copyright © 2011-2022 走看看