zoukankan      html  css  js  c++  java
  • 石子合并动态规划

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

    编一程序,由文件读入堆数N及每堆的石子数(≤20),      

    ①     选择一种合并石子的方案,使得做N-1次合并,得分的总和最小;      

    ②     选择一种合并石子的方案,使得做N-1次合并,得分的总和最大。    

    例如,所示的4堆石子,每堆石子数(从最上面的一堆数起,顺时针数)依次为4 5 9 4。则3次合并得分总和最小的方案:8+13+22=43得分最大的方案为:22+18+22=54

    解题思路:

    根据题意来拟定状态,dp[i][j]从i到j堆石子合并所得总分最大或者最小。

    利用分治的思想我们就可以看得出来,我们首先将每相邻的两堆石子合并得到一个得分,然后再扩展到3堆石子合并,3堆由两堆石子的合并情况推出,这样便形成了一种递推的效果,n堆自然能够推断到,只是注意,本题是围绕操场所以最后的石子与起始石子相邻。

    View Code
     1 #include<iostream>
     2 const int  N = 102;
     3 using namespace std;
     4 int sum[N*2][N*2],tt[N*2][N*2],n; 
     5 int main()
     6 {
     7     while(scanf("%d",&n)!=EOF)
     8     {
     9            memset(sum,0,sizeof(sum));
    10            for(int i=1;i<=n;i++)
    11                scanf("%d",&sum[i][i]);
    12            for(int i=n+1;i<2*n;i++)sum[i][i]=sum[i-n][i-n];
    13            for(int i=1;i<2*n;i++)
    14            {
    15                for(int j=i+1;j<2*n;j++)
    16                {
    17                    sum[i][j]+=sum[i][j-1]+sum[j][j]; 
    18                }
    19            }
    20           for(int i=1;i<2*n;i++)
    21               for(int j=1;j<2*n;j++)
    22                  if(i==j)
    23                  tt[i][j]=0;
    24                  else
    25                  tt[i][j]=100000000;
    26           for(int i=2;i<=n;i++)
    27                for(int j=1;j<2*n-i+1;j++)
    28                {
    29                    for(int k=j;k<j+i-1;k++)
    30                    {        
    31                        tt[j][j+i-1]=min(tt[j][k]+tt[k+1][j+i-1]+sum[j][j+i-1],tt[j][j+i-1]);
    32                    }
    33                }
    34           int mi=0x7fffffff;
    35           for(int i=1;i<=n;i++)
    36               if(tt[i][i+n-1]<mi)mi=tt[i][i+n-1];
    37           printf("%d\n",mi);
    38           memset(tt,0,sizeof(tt));
    39           for(int i=2;i<=n;i++)
    40                for(int j=1;j<2*n-i+1;j++)
    41                {
    42                    for(int k=j;k<j+i-1;k++)
    43                    {        
    44                        tt[j][j+i-1]=max(tt[j][k]+tt[k+1][j+i-1]+sum[j][j+i-1],tt[j][j+i-1]);
    45                    }
    46                }
    47           mi=0;
    48           for(int i=1;i<=n;i++)
    49              if(tt[i][i+n-1]>mi)mi=tt[i][i+n-1];
    50           printf("%d\n",mi);
    51     }
    52     return 0;    
    53 }
  • 相关阅读:
    第二高的薪水
    leecode 删除排序数组中的重复项
    leecode 17. 电话号码的字母组合
    dubbo 限流之TpsLimitFilter
    G1总结
    leecode 3. 无重复字符的最长子串
    mysql是如何解决脏读、不可重复读、幻读?
    归并排序
    PostgreSQL管理数据库安全
    Oracle Database 19c 技术架构(三)
  • 原文地址:https://www.cnblogs.com/nuoyan2010/p/2734530.html
Copyright © 2011-2022 走看看