問題描述如下:
一個公司要給多個部門分配辦公室空間,總的空間是一定的,分配空間所需的時間正比於空間的大小
比如, 總的空間的大小是1000,需要花費1000個單位時間來劃分這些時間(不管是劃分成300+700,還是劃分爲500 + 500,都是花費相同的時間)
但是總的時間取決於劃分的順序
比如總的空間數是800,每個部門的空間大小是100,200,500
如果首先劃分成100和700, 然後再把700劃分成200+500, 則總的時間是800+700 = 1500
但是如果首先劃分爲500和300,然後把300劃分成100+200,則總的時間是800+300= 1100
可見不同的劃分方法,所用的時間是不一樣的,現在要求完成最終的劃分所需的最少時間。
思路:
每次從劃分集合中刪除最小的二個數,將這二個數之和加到總時間中去,同時二個數之和作爲一個新的數放到劃分集合中去,再重複以上步驟,直到最後剩下一個數
那麼用什麼數據結構來取最小的二個數最方便呢?這裏選擇用最小堆
實現:
#include <iostream>
using namespace std;
template <typename T> // 定義一個模板類
class MiniHeap
{
public:
MiniHeap(int n);
~MiniHeap();
T pop(); // 彈出並返回堆頂的元素,也就是最小的元素
void push(T key); // 將key這個元素插入到堆中,並且插入後要保證是最小堆
int size() ;
void print();
private:
void bottomAdjust(int pos); //從某個位置開始從下往上調整
void topAdjust(int start, int end); //從堆頂位置從上往下調整
private:
T* heap; //指向堆數組的指針
int curSize; // 指示當前有多少個數在堆中,同時指示下一個要入堆的元素在調整前應該存放的位置
int maxSize; // 最小堆中最多能存放多少個元素
};
// 初始化一個堆
template <typename T> // 模板類實現方法
MiniHeap<T>::MiniHeap(int n)
{
maxSize = n;
curSize = 0;
heap = new T[maxSize];
}
template <typename T>
MiniHeap<T>::~MiniHeap()
{
curSize = 0;
maxSize = 0;
delete [] heap;
}
template <typename T>
int MiniHeap<T>::size()
{
return curSize;
}
template <typename T>
void MiniHeap<T>::print()
{
int i = 0;
for(; i < curSize; i++)
{
cout << heap[i] << " ";
}
cout << endl;
}
template <typename T>
T MiniHeap<T>::pop()
{
// 取堆頂元素返回
T top = heap[0];
// 刪除堆頂的元素,就是將最後的元素覆蓋上來,進行一次至上而下的調整
curSize --;
heap[0] = heap[curSize];
topAdjust(0,curSize-1);
return top;
}
template <typename T> // 每個方法的實現,都有template < typename T> 在前面表示這是一個模板類的方法,模板類型T
void MiniHeap<T>::topAdjust(int start, int end)
{
int parent = start;
int child = 2 * parent + 1;
T temp = heap[parent]; //先保留這個元素,等到至上而下調整完畢之後,在將它放入合適的位置
while( child <= end) //循環可能在循環終止條件退出,也可能在中間的某個時候退出
{
// 從上往下,跟top比較
if( child < end && heap[child + 1] < heap[child])
{
child++; // 將左右孩子中的較小的一個換上來
}
if( temp < heap[child]) // 如果某個時候,先前保留的元素已經小於child,那說明這個temp值應該放在parent位置上
{
break;
}
else
{
heap[parent] = heap[child];
parent = child;
child = 2 * child + 1;
}
}
heap[parent] = temp;
}
// 假設目前堆空間足夠插入
template <typename T>
void MiniHeap<T>::push( T key)
{
heap[curSize] = key;
bottomAdjust(curSize);
curSize++;
}
template <typename T>
void MiniHeap<T>::bottomAdjust(int pos)
{
// 從 pos 開始從下往上調整,跟父親比,如果比父親小則跟父親交換
int child = pos;
int pivot = heap[pos];
int parent = (child-1)/2;
while( child > 0 && pivot < heap[parent]) // 如果要調整的元素比它的父親小 // 如果這二個條件中有一個條件不滿足了,就退出了循環
{
// 將父親拉下來
heap[child] = heap[parent];
child = parent;
parent = (parent-1)/2;
}
heap[child] = pivot;
}
int N;
int data[10001];
int ptime;
int main(int argc, char** argv)
{
int test_case;
int T;
const char* INPUTFILE(TCDIR "sample_input_case.txt");
cout << INPUTFILE << endl;
freopen(INPUTFILE,"r",stdin);
cin >> T;
for(test_case = 0; test_case < T; test_case++)
{
int i;
cin >> N;
MiniHeap<int>* heap = new MiniHeap<int>(N);
for(i=1; i<=N; i++) {
cin >> data[i];
heap->push(data[i]);
// heap->print();
}
ptime = 0;
while( heap->size() > 1)
{
int a = heap->pop();
int b = heap->pop();
int partition = a+b;
ptime += partition;
heap->push(partition);
}
cout << ptime << endl;
}
return 0;
}