acwing149

这道题基本逻辑很简单,使用一个优先队列模拟哈夫曼树的建立。有这几个注意点:
从优先队列选结点构建新的节点时要注意判断队列的元素个数,防止出现剩余结点数少于叉数的情况。
每次选结点要先按照权值从小到大找结点,若权值相同再按照结点的深度从小到大找。可以自定义优先队列的比较函数,也可以使用pair来存储这两个属性。
对多叉树而言,叶子的个数n与叉数k必须满足以下条件:
\((n-1)\%(k-1)=0\)
所以要先加入一些虚结点,使之满足该条件
代码如下:

#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

#define ll long long

//用于优先队列
struct node {
	ll w;		//权值
	int depth;	//深度
	node(ll _w,int _d):w(_w),depth(_d){}
};

//用于结点间比较的函数
struct cmp {
	bool operator()(const struct node& a, const struct node& b) {
		if (a.w != b.w)		return a.w > b.w;
		return a.depth > b.depth;
	}
};

//优先队列
priority_queue<struct node, vector<struct node>, cmp> pq;

int main(void) {
	//n种单词,k进制str
	int n, k;	cin >> n >> k;
	for (int i = 0; i < n; i++) {
		ll w;	cin >> w;	pq.push(node(w,0));
	}	

	//对于多叉树,加入虚的叶子结点(坑)
	while ((n - 1) % (k - 1)) {
		n++;
		pq.push(node(0, 0));
	}

	//ans:总的最短长度	minlen:最长字串的最短长度
	ll ans=0,minlen=0;	
	while (pq.size()>1) {
		//储存k个元素中depth的最大值
		int maxdepth = 0;
		ll tempw=0;
		//pop出k个元素
		for (int i = 0; i < k; i++) {
			//对于剩余元素不到k个特殊处理
			if (pq.size() == 0)	break;
			tempw += pq.top().w;
			if (maxdepth < pq.top().depth)		maxdepth = pq.top().depth;
			pq.pop();
		}
		maxdepth++;
		//更新ans和minlen
		ans += tempw;
		if(minlen<maxdepth)		minlen = maxdepth;
		//加入新的结点
		pq.push(node(tempw, maxdepth));
	}

	cout << ans << endl << minlen << endl;
}
posted @ 2022-06-02 19:55  带带绝缘体  阅读(44)  评论(0)    收藏  举报