luogu 1090 合并果子

Posted mandy-h-y

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu 1090 合并果子相关的知识,希望对你有一定的参考价值。

合并果子
题目
[luogu1090]

题目描述

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。

每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。

因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。

假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。

输入
输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。

输出
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。

输入输出样例

输入 #1 复制
3
1 2 9
输出 #1 复制
1
说明/提示
对于30%的数据,保证有n≤1000:

对于50%的数据,保证有n≤5000;

对于全部的数据,保证有n≤10000。

 

分析

决策单调。


这道题与[luogu1880石子合并]有相似之处

但是是完全不同的两道题,这道题可以任两堆合并而石子合并只能相邻合并。

但就是这点区别,使两道题不同

对于合并果子,可以贪心的每次选最小的两堆,反正合并的次数都是一样的,先合并的后面对答案的贡献会多一点,所以要先合并小的。

但对于石子合并,因为只能合并相邻的两堆,不能保证是最小的两堆,便不能贪心了,合并的是相邻区间,区间动规会更加适合

我们回到合并果子,这道题是决策单调,每次的选择:

1.是原数列中的最小两个数

2.合并过的最小两个数

3.一个合并过,一个没合并

我们用两个队列,一个存没合并过的,一个存合并过的

现将没合并过的排序

因为都是从小到大,所以后加入的一定比先加入的大

保证了两个队列的单调性

代码

技术图片
 1 /************************
 2 User:Mandy.H.Y
 3 Language:c++
 4 Problem:luogu1090
 5 Algorithm: 
 6 ************************/
 7 #include<bits/stdc++.h>
 8 
 9 using namespace std;
10 
11 const int maxn = 1e4 + 5;
12 
13 int n,l1,r1,l2,r2;
14 long long ans;
15 long long q[maxn],a[maxn];
16 
17 template<class T>inline void read(T &x)
18     x = 0;bool flag = 0;char ch = getchar();
19     while(!isdigit(ch)) flag |= ch == -,ch =  getchar();
20     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch =  getchar();
21     if(flag) x = -x;
22 
23 
24 template<class T>void putch(const T x)
25     if(x > 9) putch(x / 10);
26     putchar(x % 10 | 48);
27 
28 
29 template<class T>void put(const T x)
30     if(x < 0) putchar(-),putch(-x);
31     else putch(x);
32 
33 
34 void file()
35     freopen("testdata(1).in","r",stdin);
36 //    freopen("1090.out","r",stdin);
37 
38 
39 void readdata()
40     read(n);
41     for(int i = 1;i <= n; ++ i)
42         read(a[i]);
43     
44 
45 
46 void work()
47         l1 = 1,r1 = n + 1;
48     sort(a + 1,a + 1 + n);
49     l2 = r2 = 0;
50     for(int i = 1;i < n; ++ i)
51         long long x1,x2,x3,x4,x = 0;
52         if(l1 < r1) x1 = a[l1];
53         else x1 =1e15;
54         if(l1 < r1-1) x2 = a[l1 + 1];
55         else x2 = 1e15;
56         if(l2 < r2) x3 = q[l2];
57         else x3 =1e15;
58         if(x3 > x1)
59             x += x1;l1++;
60             if(x3 > x2) x+=x2,l1++;
61             else x += x3,l2++;
62         else
63             x += x3;l2++;
64             if(l2 < r2) x4 = q[l2];//这里l2已经++ 
65             else x4 = 1e15;
66             if(x4 < x1) x += x4,l2++;
67             else x += x1,l1++;
68         
69         q[r2++] = x;
70         ans += x;
71     
72     put(ans);
73 
74 
75 int main()
76 //    file();
77     readdata();
78     work();
79     return 0;
80 
View Code

 

以上是关于luogu 1090 合并果子的主要内容,如果未能解决你的问题,请参考以下文章

P1090 合并果子

洛谷P1090 合并果子

洛谷 1090合并果子

P1090 合并果子

洛谷P1090 合并果子

P1090 合并果子(哈弗曼树)