• 2298 石子合并 2008年省队选拔赛山东


    题目描述 Description

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

      试设计一个算法,计算出将N堆石子合并成一堆的最小得分。

    输入描述 Input Description

      第一行是一个数N。

      以下N行每行一个数A,表示石子数目。

    输出描述 Output Description

      共一个数,即N堆石子合并成一堆的最小得分。

    样例输入 Sample Input

    4

    1

    1

    1

    1

    样例输出 Sample Output

    8

    数据范围及提示 Data Size & Hint

    对于 30% 的数据,1≤N≤100

    对于 60% 的数据,1≤N≤1000

    对于 100% 的数据,1≤N≤40000

    对于 100% 的数据,1≤A≤200

    思路:

          1. 这类题目一开始想到是DP, 设dp[i][j]表示第i堆石子到第j堆石子合并最小得分.

             状态方程: dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);

             sum[i]表示第1到第i堆石子总和. 递归记忆化搜索即可.

          2. 不过此题有些不一样, 1<=n<=50000范围特大, dp[50000][50000]开不到这么大数组.

             问题分析:

             (1). 假设我们只对3堆石子a,b,c进行比较, 先合并哪2堆, 使得得分最小.

                  score1 = (a+b) + ( (a+b)+c )

                  score2 = (b+c) + ( (b+c)+a )

                  再次加上score1 <= score2, 化简得: a <= c, 可以得出只要a和c的关系确定,

                  合并的顺序也确定.

             (2). GarsiaWachs算法, 就是基于(1)的结论实现.找出序列中满足stone[i-1] <=

                  stone[i+1]最小的i, 合并temp = stone[i]+stone[i-1], 接着往前面找是否

                  有满足stone[j] > temp, 把temp值插入stone[j]的后面(数组的右边). 循环

                  这个过程一直到只剩下一堆石子结束.

             (3). 为什么要将temp插入stone[j]的后面, 可以理解为(1)的情况

                  从stone[j+1]到stone[i-2]看成一个整体 stone[mid],现在stone[j],

                  stone[mid], temp(stone[i-1]+stone[i-1]), 情况因为temp < stone[j],

                  因此不管怎样都是stone[mid]和temp先合并, 所以讲temp值插入stone[j]

                  的后面是不影响结果.

     

     1 #include<cstdio>
     2 #include<iostream>
     3 #define ll long long
     4 #define MAXN 50010
     5 using namespace std;
     6 int t=1,n,a[MAXN];
     7 ll ans=0;
     8 inline void read(int&x) {
     9     x=0;char c=getchar();
    10     while(c>'9'||c<'0') c=getchar();
    11     while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();
    12 }
    13 inline void go(int k) {
    14     int temp=a[k-1]+a[k];
    15     ans+=temp;
    16     for(int i=k;i<t-1;i++) a[i]=a[i+1];
    17     t--;
    18     int j=0;
    19     for(j=k-1;j>0&&a[j-1]<temp;j--)
    20       a[j]=a[j-1];
    21     a[j]=temp;
    22     while(j>=2&&a[j]>=a[j-2]) {
    23         int p=t-j;
    24         go(j-1);
    25         j=t-p;
    26     }
    27 }
    28 int main() {
    29     read(n);
    30     for(int i=0;i<n;i++) read(a[i]);
    31     for(int i=1;i<n;i++) {
    32         a[t++]=a[i];
    33         while(t>=3&&a[t-3]<=a[t-1]) go(t-2);
    34     }
    35     while(t>1) go(t-1);
    36     printf("%lld
    ",ans);
    37     return 0;
    38 } 
    View Code


    作者:乌鸦坐飞机
    出处:http://www.cnblogs.com/whistle13326/
    新的风暴已经出现 怎么能够停止不前 穿越时空 竭尽全力 我会来到你身边 微笑面对危险 梦想成真不会遥远 鼓起勇气 坚定向前 奇迹一定会出现

     
  • 相关阅读:
    informix数据库的日志
    javaScript之BOM操作2
    javaScript之BOM操作1
    开发必会系列:hibernate事务
    性能测试系列:Oracle数据库awr报告使用与分析
    《股票大作手回忆录》读书笔记
    金融知识学习综合笔记
    开发必会系列:《深入理解JVM(第二版)》读书笔记
    基础教材系列:计算机底层知识点积累
    基础教材系列:数据结构与算法——慕课网笔记
  • 原文地址:https://www.cnblogs.com/whistle13326/p/6359076.html
Copyright © 2020-2023  润新知