11079 可以移动的石子合并(贪心)

11079 可以移动的石子合并

时间限制:1000MS  内存限制:1000K

提交次数:0 通过次数:0

题型: 编程题   语言: C++;C;VC;JAVA

Description

有n堆石子形成一行(a1,a2,…,an,ai为第i堆石子个数),现要将石子合并成一堆,规定每次可选择至少2堆最多k堆移出然后合并,每次合并的分值为新堆的石子数。
若干次合并后,石子最后肯定被合并为一堆,得分为每次合并的分值之和。
现在求解将这n堆石子合并成一堆的最低得分和最高得分。

输入格式

两行。第一行n和k,第二行a1 a2 … an,每个ai(1<=i<=n)表示第i堆石子的个数,n<=100,2<=k<=n。

输出格式

仅一行,为石子合并的最低得分和最高得分,中间空格相连。

输入样例

7 3
45 13 12 16 9 5 22

输出样例

199 593

提示

此题贪心算法求解.
给这题标记标签"dp"方法是同学所为,并非老师标注.动规不是不可以,但有更好更快的贪心解法的.

如7堆石头,每次可选择最少2堆最多3堆合并,可以如下这样合并:
第1次合并:45+22=67
第2次合并:67+16=83
第3次合并:83+13=96
第4次合并:96+12=108
第5次合并:108+9=117
第6次合并:117+5=122
合并的总分值:67+83+96+108+117+122=593,593已是最大分值。

也可以这样合并:
第1次合并:5+9+12=26
第2次合并:13+16+22=51
第3次合并:45+51+26=122
合并的总分值:26+51+122=199,199已是最小分值。

因此此题贪心的方法如下:

(1)保证每次选两堆最多的,合并直至只剩一堆为止,能获得最大得分;
这个和huffman树构造是相同的,不再详述!

(2)保证每次选k堆最少的,合并直至只剩一堆为止,能获得最小得分。
这个是多元huffman树的构造。要注意的是:在合并之前,若n%(k-1)!=1,说明合并到最后一轮时,剩下不是k堆(而是比k堆少),这样算的并不是最小得分,
而必须在合并之前添加若干个为0的虚拟堆,目的为凑成的堆数保证每次都能有k堆合并(包括最后一次)最后合并为1堆。
因此,在合并前作如下处理:

//假设石头每堆个数放于stone[1]~stone[n],且stone[n]之后最多k-1个数组单元为可写;
while (n % (k - 1) != 1)
{
        n++;
        stone[n]=0;
}

作者

zhengchan

我的实现代码:

其中sort()用插入排序替换更佳

#include <iostream>
#include <algorithm>

using namespace std;
/*
测试数据:

7 3
45 13 12 16 9 5 22

6 3
1 2 3 4 5 6

*/

int main()
{
    int n,k;
    cin >> n >> k;

    int stone[n+10];

    for (int i = 0; i < n; i++) {
        cin >> stone[i];
    }

    int cur;
    int minC = 0,maxC = 0;
    int minTemp, maxTemp;

    sort(stone, stone + n);

    cur = n-1;
    maxTemp = stone[cur];
    while (cur != 0) {// 求最大
        maxTemp = maxTemp + stone[cur - 1];
        maxC += maxTemp;
        cur--;
    }

//  ========================================================================

    //假设石头每堆个数放于stone[1]~stone[n],且stone[n]之后最多k-1个数组单元为可写;
    while (n % (k - 1) != 1) {
        stone[n++] = 0;
    }

    sort(stone, stone + n);

    cur = 0;
    minTemp = stone[cur];
    while (cur <= n - k) {// 求最小

        for (int i = 0; i < k - 1; i++) {
            stone[cur + k-1] += stone[cur + i];
        }
        minC += stone[cur + k-1];
        cur += k-1;

        sort(stone, stone + n);
//        for (int i = 0; i < n; i++) {
//            cout << stone[i] << " ";
//        }
//        cout << endl;
    }

    cout << minC << " " << maxC;

    cout << endl;
    return 0;
}
时间: 2024-10-25 06:19:41

11079 可以移动的石子合并(贪心)的相关文章

(转)石子合并问题

本文转自 http://blog.csdn.net/acdreamers/article/details/18039073 石子合并问题是最经典的DP问题.首先它有如下3种题型:   (1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量.求将这N堆石子合并成一堆的总花费最小(或最大). 分析:当然这种情况是最简单的情况,合并的是任意两堆,直接贪心即可,每次选择最小的两堆合并.本问题实际上就是哈夫曼的变形.     (2)有N堆石

DP经典题型:石子合并问题

本周集训专题为DP系列,一个经典的系列便是石子归并问题. (1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量.求将这N堆石子合并成一堆的总花费最小(或最大). 这是石子归并的简化版本,石子处于一排.由于发现只能是相邻的2堆石子进行归并.我们会发现,贪心算法在此处便失去作用,局部最优解并不能带来整体最优解. 因此,不难让我们想到,此题应该采取DP(dynamic Programing)来求其最优解. 动态规划常常采取从部分整体最

[08山东省选]2298 石子合并

2298 石子合并 2008年省队选拔赛山东 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 在一个操场上摆放着一排N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将N堆石子合并成一堆的最小得分. 输入描述 Input Description 第一行是一个数N. 以下N行每行一个数A,表示石子数目. 输出描述 O

四边形不等式优化_石子合并问题_C++

在动态规划中,经常遇到形如下式的状态转移方程: m(i,j)=min{m(i,k-1),m(k,j)}+w(i,j)(i≤k≤j)(min也可以改为max) 上述的m(i,j)表示区间[i,j]上的某个最优值.w(i,j)表示在转移时需要额外付出的代价.该方程的时间复杂度为O(N3) 下面我们通过四边形不等式来优化上述方程,首先介绍什么是“区间包含的单调性”和“四边形不等式” 1.区间包含的单调性:如果对于 i≤i'<j≤j',有 w(i',j)≤w(i,j'),那么说明w具有区间包含的单调性.

动态规划思想:石子合并问题

描述:在一个圆形操场的四周摆放着n 堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分.试设计一个算法,计算出将n堆石子合并成一堆的最小得分和最大得分. 贪心算法不能得到最优解,可惜了.首先我们可以把这么堆石子看成一列 如果N-1次合并的全局最优解包含了每一次合并的子问题的最优解,那么经这样的N-1次合并后的得分总和必然是最优的.因此我们需要通过动态规划算法来求出最优解. 在此我们假设有n堆石子,一字排开,合并相邻两堆的石子,

P5569 【SDOI2008】 石子合并(黑科技)

\(Solution\) 当\(n\)在\(100\)左右时,直接\(O(n^3)\)区间\(DP\) 当\(n\)在\(40000\)左右时,需要用贪心算法:加西亚-瓦克斯算法(\(Garsia\ Wachs\)) 注:这个方法仅求石子合并的最小答案 这是大概的流程 这是关于\(Garsia\ Wachs\)算法的正确性证明:传送门 时间复杂度最坏为\(O(n^2)\),但是基本跑不满,数据随机的话\(n=40000\)能搞过去 代码使用链表实现,方便删除和插入操作,边界什么的比较麻烦,一定要

BZOJ 3229: [Sdoi2008]石子合并

3229: [Sdoi2008]石子合并 时间限制: 3 Sec  内存限制: 128 MB提交: 497  解决: 240[提交][][] 题目描述 在一个操场上摆放着一排N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将N堆石子合并成一堆的最小得分. 输入 第一行是一个数N. 以下N行每行一个数A,表示石子数目. 输出 共一个数,即N堆石子合并成一堆的最小得分. 样例输入 4 1 1 1 1 样

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

题目描述 Description 在一个操场上摆放着一排N堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 试设计一个算法,计算出将N堆石子合并成一堆的最小得分. 输入描述 Input Description 第一行是一个数N. 以下N行每行一个数A,表示石子数目. 输出描述 Output Description 共一个数,即N堆石子合并成一堆的最小得分. 样例输入 Sample Input 4 1 1 1 1 样例输出 S

四边形不等式优化DP——石子合并问题 学习笔记

好方啊马上就要区域赛了连DP都不会QAQ 毛子青<动态规划算法的优化技巧>论文里面提到了一类问题:石子合并. n堆石子.现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分. 求出将n堆石子合并成一堆的最小得分和最大得分以及相应的合并方案. 设m[i,j]表示合并d[i..j]所得到的最小得分. 状态转移方程: 总的时间复杂度为O(n3). [优化方案] 四边形不等式: m[i,j]满足四边形不等式 令s[i,j]=max{k | m[