• Luogu P1880 石子合并


     P1880 石子合并

    题目描述

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

      石子合并问题是经典问题。主要分为3类:1、任意两堆石子合并。2、链状相邻两堆石子合并。3、环状的相邻两堆石子合并。

      假设石子合并问题要求合并所得最小值(最大值与最小值一个道理,这里只讲最小值)。

      第一类: 每次找出最小的两堆石子进行合并。可以采用优先队列实现。

      第二类:dp。 dp[i][j] 是从i到j合并石子,所需要最小值。

      转移方程是 dp[i][j] = min(dp[i][j], dp[i][i+k]+dp[i+k+1][j])+sum[i][j]。

      sum[i][j]是表示i到j的石子和。 dp[i][i+k]+dp[i+k+1][j]的意思是不断的分成两堆,看哪两堆是最小值。

      边界条件是dp[i][i] = 0 因为这堆和本身合并不得分。

      第三类:dp。 其实是第二类的变形,只需要 断环为链 就可以。

      详细看代码吧。

     1 #include <cstdio>
     2 
     3 #define ll long long
     4 #define INF 1<<30
     5 //开long long,不然f会爆。。。
     6 ll aa[210],f1[210][210],f2[210][210],w[210], ans1, ans2;    //f1->min  f2->max
     7 //f1是求最小得分 f2是求最大得分
     8 ll Min(ll a, ll b)
     9 {
    10     return (a < b ? a : b);
    11 }
    12 ll Max(ll a, ll b)
    13 {
    14     return (a > b ? a : b);
    15 }
    16 
    17 int main()
    18 {
    19     int n;
    20     scanf("%d", &n);
    21     for(int i=1; i<=n; i++)
    22     {
    23         scanf("%lld", &aa[i]);
    24         aa[i+n] = aa[i];//断环为链
    25     }
    26     for(int i=1; i<2*n; i++)
    27         w[i] = w[i-1] + aa[i];//处理前缀和
    28     //v表示当前合并i到第i+v个石子 最多合并i到 i+n-1个石子
    29     for(int v=1; v<n; v++)
    30         for(int i=1; i<2*n-v; i++)
    31         {
    32             f1[i][i+v] = INF;
    33             f2[i][i+v] = 0;
    34             for(int k=0; k<v; k++)
    35             {    //这里一定要检查是否拼错 我就因为把f2写成了f1而导致WA 查错好长时间才找出来
    36                 //注意f1与min对应 f2与max对应。
    37                 f1[i][i+v] = Min(f1[i][i+v], f1[i][i+k]+f1[i+k+1][i+v]);
    38                 f2[i][i+v] = Max(f2[i][i+v], f2[i][i+k]+f2[i+k+1][i+v]);
    39             }//不要忘记加他们的sum
    40             f1[i][i+v] += (w[i+v] - w[i-1]);
    41             f2[i][i+v] += (w[i+v] - w[i-1]);
    42         }
    43     
    44     
    45     ans1 = INF; ans2 = 0;
    46     //寻找结果
    47     for(int i=1; i<=n; i++)
    48     {
    49         ans1 = Min(ans1, f1[i][i+n-1]);
    50         ans2 = Max(ans2, f2[i][i+n-1]);
    51     }
    52     
    53     printf("%lld
    %lld", ans1, ans2);
    54     return 0;
    55 }
  • 相关阅读:
    K近邻 Python实现 机器学习实战(Machine Learning in Action)
    sklearn-SVC实现与类参数
    从核函数到SVM原理--sklearn-SVM实现
    基于scikit-learn包实现机器学习之KNN(K近邻)-完整示例
    java集合框架
    面向对象第一周心得体会
    java面试总结
    Aaa
    测试
    在Java中执行Tomcat中startup.bat
  • 原文地址:https://www.cnblogs.com/yBaka/p/7754084.html
Copyright © 2020-2023  润新知