在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过 n − 1 n-1 n−1 次合并之后, 就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为 1 1 1 ,并且已知果子的种类 数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 3 3 种果子,数目依次为 1 1 1 , 2 2 2 , 9 9 9 。可以先将 1 1 1 、 2 2 2 堆合并,新堆数目为 3 3 3 ,耗费体力为 3 3 3 。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为 12 12 12 ,耗费体力为 12 12 12 。所以多多总共耗费体力 = 3 + 12 = 15 =3+12=15 =3+12=15 。可以证明 15 15 15 为最小的体力耗费值。
共两行。
第一行是一个整数
n
(
1
≤
n
≤
10000
)
n(1\leq n\leq 10000)
n(1≤n≤10000) ,表示果子的种类数。
第二行包含 n n n 个整数,用空格分隔,第 i i i 个整数 a i ( 1 ≤ a i ≤ 20000 ) a_i(1\leq a_i\leq 20000) ai(1≤ai≤20000) 是第 i i i 种果子的数目。
一个整数,也就是最小的体力耗费值。输入数据保证这个值小于 2 31 2^{31} 231 。
3
1 2 9
15
对于 30 % 30\% 30% 的数据,保证有 n ≤ 1000 n \le 1000 n≤1000:
对于 50 % 50\% 50% 的数据,保证有 n ≤ 5000 n \le 5000 n≤5000;
对于全部的数据,保证有 n ≤ 10000 n \le 10000 n≤10000。
思路,这个题我第一次的想法就是把数据从小到大,然后依次合并,最后就能得到结果!
后来发现,虽然最小的两个合并,但是可能两个小的合并后的数据大于下一个,再次合并就是有问题的,因此,我又想到一种方法,就是每次遍历找到最小的两个,然后将这两个合并成一个大数字,然后把当初小的那个数字变成-1,然后把大数字赋值到数组内,再进行一次遍历,找到最小的两个,又进行合并,这样每次我遍历时候都把负数去掉,以此循环遍历能得到最后的结果!
该算法的时间复杂度是O(n*n)(应该不算优),如果广大网友有更好的想法,欢迎q我!
代码如下(编译器是dev,语言是C语言):
#include
int n,a[10005],temp,i,j,sum=0,minmin,minmax,mintemp=0,maxtemp=1,k,s,tempshuzu;
int main(){
scanf("%d",&n);
for(i = 1;i<=n;i++){
scanf("%d",&a[i]);
}
minmin = a[1],minmax = a[2];
mintemp = 1,maxtemp = 2;
for(i = 1;i<n;i++){
for(s = 1;s<=n;s++){
if(a[s]<0)
continue;
minmin = a[s];
mintemp = s;
break;
}
for(s = 1;s<=n;s++){
if((a[s]<0)||(s == mintemp))
continue;
minmax = a[s];
maxtemp = s;
break;
}
if(minmax<minmin){
temp = minmax;
minmax = minmin;
minmin = temp;
tempshuzu = mintemp;
mintemp = maxtemp;
maxtemp = tempshuzu;
}
for(j = 1;j<=n;j++){
if(a[j] <0){
continue;
}
if((a[j]<minmax)&&(j!=mintemp)){
if(a[j]<minmin){
minmax = minmin;
minmin = a[j];
//minmax = minmin;
maxtemp = mintemp;
mintemp = j;
}else{
minmax = a[j];
maxtemp = j;
}
}
}
sum = sum + minmin +minmax;
a[maxtemp] = minmin+minmax;
a[mintemp] = -1;
}
printf("%d",sum);
return 0;
}