CSU 1588 合并果子(详细优先队列+贪心+堆)

CSU 1588 合并果子(详细优先队列)

现在有n堆果子,第i堆有ai个果子。现在要把这些果子合并成一堆,每次合并的代价是两堆果子的总果子数。求合并所有果子的最小代价。

Input
第一行包含一个整数T(T<=50),表示数据组数。
每组数据第一行包含一个整数n(2<=n<=1000),表示果子的堆数。
第二行包含n个正整数ai(ai<=100),表示每堆果子的果子数。

Output
每组数据仅一行,表示最小合并代价。

Sample Input
2
4
1 2 3 4
5
3 5 2 1 4
Sample Output
19
33

个人分析:

通过读这一小段短文,我们知道这是关于贪心类的题目,要求出最小合并代价 对于样例1我先解释一下19怎么得到的:1 2 3 4 先取1和2 这时代价为3 再取3和3 这时代价为3+3=6 最后取4 代价为6+4=10 注意加粗的地方 全部相加3+6+10=19
从里面我们可以得到什么呢?首先,要获得最小合并代价 就需要从最小的开始加 一直加到最大的(也就是类似1 2 3 4 这样从小到大取)

然后,我们取了2堆果子后 合并后的代价在下一次还要再与下一堆果子相加 也就是结果还需要放入堆(优先队列)里面 优先队列也可以说是堆哦 所以这个题也提示的很明白了

priority_queue<int,vector<int>,greater<int> > q;
 
 for(int i=1;i<n;i++)
        {
            int w=q.top();
            q.pop();
            w+=q.top();
            q.pop();
            sum+=w;
            q.push(w);
        }

对于以上代码:
优先队列有一个功能是元素在入队的同时进行自动排序,默认非升序;这时候需要自定义排序类型,然后每次把队列的前两个元素加起来再入队。
我们申明了以上代码形式的优先队列 greater是用来取大的放入前面 比如样例1 放进去会自动排列为4 3 2 1 那通过之前的分析我们是需要从小到大取,这不是错了吗? 这个没错哦!放进去 4 3 2 1 但是我们取的时候取得栈顶top() 相当于1 2 3 4 的来取 这也是我一开始没想明白的地方,所以以后遇到优先队列要从小到大取,那么我们放的时候就从大到小来放。

然后,对于下面for循环 为什么i从1开始,因为我们要一次取2个 并且结果还要保留为了下次计算,所以循环次数-1 用w来记录每次拿两堆果子的合并代价 然后sum用来求每次w的总和。

个人感受:

这个题被很多人说是水题,但是我还是不觉得,我也是思考了许久才做出来的,原因在于对于这个优先队列还不是很清楚,后面查了资料然后自己写了一段关于这个题的优先队列 一下恍然大悟 这种感觉很舒服~
具体代码如下:
AC

#include
#include
#include
#include
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        int sum=0;
        for(int i=0;i<n;i++)
        {
            int x;
            cin>>x;
            q.push(x);
        }
        for(int i=1;i<n;i++)
        {
            int w=q.top();
            q.pop();
            w+=q.top();
            q.pop();
            sum+=w;
            q.push(w);
        }
        cout<<sum<<endl;
    }

    return 0;
}

学如逆水行舟,不进则退

你可能感兴趣的:(算法)