题目
有n个数的集合S,每次可以从S中删除两个数,然后把它们的和放回集合,直到剩下一个数。每次操作的开销等于剩下的两个数之和,求解最小的总开销。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <functional>
#include <queue>
using namespace std;
int main() {
int n, x;
while (scanf("%d", &n) == 1 && n) {
priority_queue<int, vector<int>, greater<int> > q;
for (int i = 0; i < n; i++) {
scanf("%d", &x);
q.push(x);
}
int ans = 0;
for (int i = 0; i < n - 1; i++) {
int a = q.top(); q.pop();
int b = q.top(); q.pop();
ans += a + b;
q.push(a + b);
}
printf("%d\n", ans);
}
return 0;
}
思路
1.参考Huffman编码树,每次取权值最小的两个,求和并插入队列。
收获
1.优先队列的使用
priority_queue<int, vector<int>, greater<int> > q;
- 优先队列默认为,值越大的越优先出列
- 此处使用greater< int>可以让值越小的越优先出列。注意,优先队列与一般stl容器不同,它的greater< int>代表的是值小出列,而less< int>代表的是值大出列。
- 也可以自定义排序方法,参考以下代码:
#include <queue>
using namespace std;
struct cmp{
bool operator ()(int a,int b){ //通过传入不同类型来定义不同类型优先级
return a>b; //最小值优先
}
};
priority_queue<int, vector<int>, cmp > q;
2.对于Huffman编码,真正在算法竞赛中用的多的,往往不是怎么写一个字符串的编码,而是其“权值小的先建树”的思想。