1. 程式人生 > 其它 >P2168 荷馬史詩

P2168 荷馬史詩

感謝所有AC

 

傳送門

思路

      k進位制的哈夫曼樹模板。

       每個結點記憶體儲權值和高度,以權值為第一關鍵詞,高度為第二關鍵詞建立一個優先佇列。每一次操作都把權值最小的 k 個數取出,合併後加入堆中(哈夫曼演算法)。在最後一次合併時可能出現堆中元素不足 k 個,如果直接合並的話會出現哈夫曼樹上還有短編碼的空位卻沒有進行填充(即得不到最優解,離樹根近的位置沒有得到利用)。所以在堆內加入權值為 0 的結點來保證所有位置的合理利用,且這樣並不會影響哈夫曼演算法的準確性。在建樹過程中計算WPL並求解最大深度。

程式碼

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
	long long w, l;
};
long long n, k, in, ans;
bool operator<(node a, node b) {
	if (a.w != b.w)return a.w > b.w;
	else return a.l > b.l;
}
//優先佇列的結構體定義有點不同,需要注意
priority_queue<node> q;
int main(void)
{
	ios::sync_with_stdio(false);
	cin >> n >> k;
	for (int i = 1; i <= n; i++)
	{
		cin >> in;
		q.push({ in,1 });
	}
	long long add = (n - 1) % (k - 1);
	if (add) {
		for (int i = 1; i <= k - 1 - add; i++)
			q.push({ 0,1 });
        //差多少補多少
	}
	while (q.size() != 1) {
		long long sum = 0, h = 0;
		for (int i = 1; i <= k; i++)
		{
			sum += q.top().w;
			h = max(h, q.top().l);//取最大深度
			q.pop();
		}
		ans += sum;
        //在構造哈夫曼樹過程中計算WPL的核心程式碼
		q.push({ sum,h + 1 });
	}
	cout << ans << '\n' << q.top().l - 1 << '\n';
	return 0;
}