题目大意:FJ需要修补牧场的围栏,他需要 N 块长度为 Li 的木头(N planks of woods)。开始时,FJ只有一块无限长的木板,因此他需要把无限长的木板锯成 N 块长度
为 Li 的木板,Farmer Don提供FJ锯子,但必须要收费的,收费的标准是对应每次据出木块的长度,比如说测试数据中 5 8 8,一开始,FJ需要在无限长的木板上锯下长度 21 的木板(5+8+8=21),第二次锯下长度为 5 的木板,第三次锯下长度为 8 的木板,至此就可以将长度分别为 5 8 8 的木板找出
题目可以转化为Huffman树构造问题 :
给定 N planks of woods,
1. 在 N planks 中每次找出两块长度最短的木板,然后把它们合并,加入到集合A中,
2. 在集合中找出两块长度最短的木板,合并加入到集合A中,重复过程,直到集合A中只剩下一个元素
显然,通过每次选取两块长度最短的木板,合并,最终必定可以合并出长度为 Sum(Li)的木板,并且可以保证总的耗费最少
AC 16MS 440K
1 #include <stdio.h> 2 #include <memory.h> 3 4 const int maxn = 20004; 5 const int INF = 0x3F3F3F3F; 6 7 int nNum; 8 __int64 heap[maxn]; 9 10 void shiftdown(int fa, int n) 11 { 12 int son; 13 __int64 key=heap[fa]; 14 for (; fa<=n>>1; fa=son) 15 { 16 son = fa<<1; /* Left_child */ 17 if (son!=n && heap[son+1]<heap[son]) 18 son = son +1; 19 20 if (key > heap[son]) 21 heap[fa] = heap[son]; 22 else 23 break; 24 }/* End of For */ 25 heap[fa] = key; 26 }/* shiftdown */ 27 28 __int64 GetHeapTop() 29 { 30 __int64 ret = heap[1]; 31 32 heap[1] = heap[nNum]; 33 heap[nNum--] = INF; 34 shiftdown(1, nNum); 35 36 return ret; 37 }/* GetHeapTop */ 38 39 void InSertToHeap(int t) 40 { 41 heap[++nNum] = t; 42 43 int p = nNum; 44 while (p!=1 && heap[p>>1]>t) 45 { 46 heap[p] = heap[p>>1]; 47 p >>= 1; 48 }/* End of While */ 49 heap[p] = t; 50 }/* InSertToHeap */ 51 52 int main() 53 { 54 int i; 55 while (~scanf("%d", &nNum)) 56 { 57 /** Initialized 58 for (i=1; i<=(nNum<<1|1); ++i) 59 heap[i] = INF; 60 ***/ 61 62 memset(heap, INF, sizeof(heap)); 63 64 /* Input */ 65 for (i=1; i<=nNum; ++i) 66 scanf("%I64d", &heap[i]); 67 68 /* Build the Min_Heap */ 69 for (i=nNum>>1; i>=1; --i) 70 shiftdown(i, nNum); 71 72 __int64 a, b, lowcost = 0; 73 while (nNum > 1) 74 { 75 a = GetHeapTop(); 76 b = GetHeapTop(); 77 78 lowcost += a+b; 79 InSertToHeap(a+b); 80 }/* End of While */ 81 82 printf("%I64d\n", lowcost); 83 }/* End of While */ 84 85 return 0; 86 }