リソース制限
時間制限:1.0秒メモリ制限:512.0 MB
問題の説明
ハフマンツリーには、コーディングにおける幅広いアプリケーションがあります。ここでは、ハフマンツリーの構築プロセスのみを扱います。
数値のリスト{pi} = {p0、p1、…、pn-1}が与えられた場合、この数値のリストを使用してハフマンツリーを作成するプロセスは次のとおりです
。1. {pi}で2つの最小の数値を見つけ、paとpbに設定します。 {pi}からpaとpbを削除し、それらの合計を{pi}に追加します。このプロセスのコストは、pa + pbとして記録されます。
2. {pi}の数が1つだけになるまで、手順1を繰り返します。
上記の操作プロセスでは、すべてのコストが加算され、ハフマンツリーを構築するための総コストが取得されます。
この問題のタスク:特定のシーケンスについて、そのシーケンスでハフマンツリーを構築するための総コストを見つけてください。
たとえば、シーケンス{pi} = {5、3、8、2、9}の場合、ハフマンツリーの構築プロセスは次のようになります
。1. {5、3、8、2、9}で最小の2つの数値をそれぞれ検索します2と3、それらを{pi}から削除し、5を追加して{5、8、9、5}を取得します。コストは5です。
2. {5、8、9、5}、5、5の最小の2つの数値を見つけ、{pi}から削除し、10を追加して{8、9、10}を取得します。コストは10です。 。
3. {8、9、10}の最小の2つの数値(8と9)を見つけ、それらを{pi}から削除し、17を追加して{10、17}を取得します。コストは17です。
4. {10、17}の中で最も小さい2つの数値(10と17)を見つけ、{pi}から削除し、27を追加して{27}を取得します。コストは27です。
5.これで、シーケンスに残っている数は27だけです。構築プロセスは終了し、総コストは5 + 10 + 17 + 27 = 59になります。
入力フォーマット入力
の最初の行には、正の整数n(n <= 100)が含まれています。
次に、p0、p1、…、pn-1を表すn個の正の整数があり、各数値は1000を超えません。
出力形式
これらの数値を使用してハフマンツリーを構築するための総コストを出力します。
サンプル入力
5
5 3 8 2 9
サンプル出力
59
問題解決のアイデア:
ハフマンツリーは比較的古典的なアルゴリズムであり、そのアプリケーションシナリオはパスワードの解読と暗号化に非常に成功しています。今日の質問は実際には非常に単純です。貪欲なアイデアで最小の2つの数値を毎回取得し、それをツリーの配列に戻し、配列に要素が1つだけになるまで繰り返します。ここで私は誰もが答えるために2つの方法を使用します。
最初の方法:最小ヒープ、データ構造を学んだ友達は、最小ヒープを書き込むプロセスが非常に難しいことを知っていますが、それは本当に香りがよいと言わなければなりません。すべての入力数値を最初に最小ヒープに入れてくださいヒープの最上位の要素が最小のヒープから取得されるたびに、最小値である必要があります。以下同様に、ヒープ内の要素が1つだけになるまで続きます。
2番目の方法:sort()関数を使用して並べ替え、毎回最小の要素を取得し、余分な要素を削除するように注意します。
2つの方法があります。
#include<bits/stdc++.h>
using namespace std;
template<class T>
class MinHeap {
private:
T *heapArray; // 存放堆数据的数组
int CurrentSize; // 当前堆中元素数目
int MaxSize; // 堆所能容纳的最大元素数目
public:
MinHeap(const int n); // 构造函数,n表示 堆的最大元素数目
virtual ~MinHeap() { delete[]heapArray; } // 析构函数
void swap(int pos_x, int pos_y); // 交换位置x和y的元素
void BuildHeap(); // 建堆
bool isEmpty(); // 如果堆空,则返回真
bool isLeaf(int pos) const; // 如果是叶结点,返回TRUE
int leftchild(int pos) const; // 返回左孩子位置
int rightchild(int pos) const; // 返回右孩子位置
int parent(int pos) const; // 返回父结点位置
bool Remove(int pos, T& node); // 删除给定下标的元素
bool Insert(const T& newNode); // 向堆中插入新元素newNode
T& RemoveMin(); // 从堆顶删除最小值
void SiftUp(int position); // 从position向上开始调整,使序列成为堆
void SiftDown(int left); // 向下筛选,参数left表示开始处理的数组下标
void show();
int getCurrentSize();
};
template<class T>
int MinHeap<T>::getCurrentSize() {
return CurrentSize;
}
template<class T>
bool MinHeap<T>::isEmpty() {
if (CurrentSize == 0) {
return true;
}
else return false;
}
template<class T>
bool MinHeap<T>::isLeaf(int pos) const {
if (pos % 2 == 1) {
return true;
}
else return false;
}
template<class T>
void MinHeap<T>::swap(int pos_x, int pos_y) {
T data = heapArray[pos_x];
heapArray[pos_x] = heapArray[pos_y];
heapArray[pos_y] = data;
}
template<class T>
void MinHeap<T>::BuildHeap() {
for (int i = CurrentSize / 2 - 1; i >= 0; i--)// 反复调用筛选函数
SiftDown(i);
}
template<class T>
MinHeap<T>::MinHeap(const int n) {
if (n <= 0) return;
CurrentSize = 0;
MaxSize = n; // 初始化堆容量为n
heapArray = new T[MaxSize]; // 创建堆空间
BuildHeap(); // 此处进行堆元素的赋值工作
}
template<class T>
int MinHeap<T>::leftchild(int pos) const {
return 2 * pos + 1; // 返回左孩子位置
}
template<class T>
int MinHeap<T>::rightchild(int pos) const {
return 2 * pos + 2; // 返回右孩子位置
}
template<class T>
int MinHeap<T>::parent(int pos) const {
return (pos - 1) / 2; // 返回父结点位置
}
template <class T>
bool MinHeap<T>::Insert(const T& newNode) { // 向堆中插入新元素newNode
if (CurrentSize == MaxSize) return false; // 堆空间已经满
heapArray[CurrentSize] = newNode;
SiftUp(CurrentSize); // 向上调整
CurrentSize++;
return true;
}
template<class T>
T& MinHeap<T>::RemoveMin() { // 从堆顶删除最小值
if (CurrentSize == 0) {
cout << "Can't Delete"; // 调用RemoveMin之前,需要判断堆非空
exit(1);
}
else {
swap(0, --CurrentSize); // 交换堆顶和最后一个元素
if (CurrentSize > 1) {
SiftDown(0); // 从堆顶开始筛选
}
return heapArray[CurrentSize];
}
}
template<class T>
bool MinHeap<T>::Remove(int pos, T& node) { // 删除给定下标的元素
if ((pos < 0) || (pos >= CurrentSize)) return false;
node = heapArray[pos];
heapArray[pos] = heapArray[--CurrentSize]; // 用最后的元素值替代删除位置的元素
if (heapArray[parent(pos)] > heapArray[pos])
SiftUp(pos); // 当前元素小于父结点,需要上升调整
else SiftDown(pos); // 当前元素大于父结点,向下筛
return true;
}
template<class T>
void MinHeap<T>::SiftUp(int position) {
// 从position向上开始调整
int temppos = position;
T temp = heapArray[temppos];
while ((temppos > 0) && (heapArray[parent(temppos)] > temp)) {
heapArray[temppos] = heapArray[parent(temppos)];
temppos = parent(temppos);
}
heapArray[temppos] = temp;
}
template <class T>
void MinHeap<T>::SiftDown(int left) {
int i = left; // 标识父结点
int j = leftchild(i); // 标识关键值较小的子结点
T temp = heapArray[i]; // 保存父结点
while (j < CurrentSize) { // 过筛
if ((j < CurrentSize - 1) && (heapArray[j] > heapArray[j + 1]))
//若有右子节点,且小于左子节点
j++; // j指向右子结点
if (temp > heapArray[j]) { //若父节点大于子节点的值则交换位置
heapArray[i] = heapArray[j];
i = j;
j = leftchild(j);
}
else break; //堆序满足,跳出
}
heapArray[i] = temp;
}
template<class T>
void MinHeap<T>::show() {
for (int i = 0;i < CurrentSize; i++)
{
cout << heapArray[i] << " ";
}
}
int main() {
MinHeap<int> heap(100);
int i, n;
cin >> n;
for(i = 0; i < n; i++) {
int data;
cin >> data;
heap.Insert(data);
}
int sum = 0;
int num = 0;
while(heap.getCurrentSize() > 1){
num += heap.RemoveMin();
num += heap.RemoveMin();
sum += num;
heap.Insert(num);
num = 0;
}
cout << sum;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[100];
int i,n;
cin >> n;
for(i = 0; i < n; i++) {
cin >> a[i];
}
sort(a,a+n);//从小到大排序
int sum = 0;
while(n > 1)
{
i=0;
a[i] = a[i] + a[i+1];
sum += a[i];
a[i + 1] = -1;//将这个数去除
sort(a,a+n);
for(i = 0;i < n-1; i++)//把-1值覆盖
a[i] = a[i+1];
n--;
}
cout << sum;
return 0;
}