[NOIP2004 提高组] 合并果子 / [USACO06NOV] Fence Repair G - 洛谷
解题思路:
1.由题可知,一共有n个数,每次都从中挑选出两个数来 进行合并,形成一个新的数,然后加入到数字中,继 续挑选两个最小的数合并,直至最后变成一个数,如 果每次合并后都将这两个数删除,加入一个数,重新 排序,显然会超出时间,所以应该利用两个数组来同 时存放原本的数字和合并好的数字
2. 第一个数组进行排序后,比较小的数都在前面,所以 可以按顺序取,第一次取前两个数来进行合并,将合 并好的数字放入第二个数组中,并且不再考虑前两个 数,第二次合并将第二个数组的数字和第一个数组中 第三第四位置的数取出两个较小值依次进行上述操作
3. 可能会想到第二个数组中会有好几个数,判断是否要 排序,将最小的数置入最前面,其实数组1已经排好 序,数组2中的数是由数组1合并来的,所以无论如 何,数组2的最小数一定在头部
4. 关于如何划掉已经合并的数,可以利用书签法来定 位,书签的位置就是没有被划掉的数,此外还要记录 两个数组中分别的元素个数,并且分别用不同的书签 去往后延伸,根据大小选取最小的两个数,每次选出 来这两个数,要把他们的和依次放入数组2中
#include<bits/stdc++.h>
using namespace std;
int a[10005],b[10005];//a数组用来存放原始数字,b数组存放已经合并的数字
int main()
{
int n;
memset(a,127,sizeof(a));//将两个数组初始化为很大的值,防止0被当成果子数合并
memset(b,127,sizeof(b));
cin>>n;
for(int i=1;i<=n;i++)//原始数据依次存入数组a
cin>>a[i];
sort(a+1,a+n+1);//快速排序,从小到大
int i=1,j=1,num,temp=1,sum=0;//i和j分别用来做数组ab的书签,num存放每次合并的果子数
//temp用来当每次num存放到数组b的位置下标
for(int k=1;k<n;k++) //n个数合并的话取n-1次即可,手动验算
{
if(a[i]<b[j])//如果数组a的值小于b
{
num=a[i];//第一个最小值是a[i]
i++;//书签往后移动
}
else//否则,第一个最小的值就是b[j],书签往后移动
{
num=b[j];
j++;
}
if(a[i]<b[j])//取第二个最小值,同理
{
num=num+a[i];
i++;
}
else
{
num=num+b[j];
j++;
}
b[temp]=num;//将合并好的数字放入数组b下标为temp的位置
temp++;//下标后移,便于下一次存储
sum=sum+num;//累加活力值
}
cout<<sum;
return 0;
}