ACM水题-合并果子(堆结构,贪心算法,AC)
2012-05-10 20:29
363 查看
合并果子
Time Limit:1000MS Memory Limit:65536K
Total Submit:285 Accepted:112
Description
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
Input
输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
Output
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。
Sample Input
Sample Output
Source
NOIP 2004
Time Limit:1000MS Memory Limit:65536K
Total Submit:285 Accepted:112
Description
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。可以先将1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。
Input
输入包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
Output
输出包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于2^31。
Sample Input
3 1 2 9
Sample Output
15
Source
NOIP 2004
/* ----------------------------------------------------- 先排序,每次找最少数量的两堆合并。再排序,再找最少数量的 两堆 。。。结果超时了。。。 ----------------------------- 正确应该是先建立一个最小堆,然后取出根,再重新整理堆, 再取出来。。。取出根,整理堆这一个操作的时间复杂度为o(lgn), 要取n-1次,所以总的时间复杂的度o(nlgn)。 之前的想法错在,每一次取完之后,就再排序一次,排一次 的平均时间为o(nlgn),n-1次,所以就变成了O(n^2lgn)。。大了足足 一个数量级,所以肯定超时。 这里没有注意到的是,在一个最小堆的基础是,取走根,然后重新整理 堆这一个操作,时间只有和堆的高度有关。。。算法导论上面也有说 “总之,一个堆可以在O(lgn)时间内,支持大小为n的集合上的任意优先队列 操作”~~~~~Orz~~~~ 状况:AC,15MS ----------------------------------------------------- */ #include<stdio.h> #define PARENT(i) ((i)/2) #define LEFT(i) (2*(i)) #define RIGHT(i) ((2*(i))+1) long a[10002] ; void MinHeapify(long i) ; long HeapExtractMin() ; void HeapInsert(long key) ; int main(void) { long n = 0 ; long i = 0 ; long nTotal = 0 ; long nLength = 0 ; long nFir = 0 ; long nSec = 0 ; scanf("%ld",&n) ; for(i = 1 ; i <= n ; ++i) { scanf("%ld",&a[i]) ; } a[0] = n ; nLength = a[0] ; for(i = nLength/2 ; i >= 1 ; --i) { MinHeapify(i) ; } while(a[0] > 1) { nFir = HeapExtractMin() ; nSec = HeapExtractMin() ; HeapInsert(nFir+nSec) ; nTotal += nFir+nSec ; } printf("%ld\n",nTotal) ; return 0 ; } void MinHeapify(long i) { long l = LEFT(i) ; long r = RIGHT(i) ; long lowest = 0 ; long temp = 0 ; do { l = LEFT(i) ; r = RIGHT(i) ; if(l <= a[0] && a[l] < a[i]) { lowest = l ; } else { lowest = i ; } if(r <= a[0] && a[r] < a[lowest]) { lowest = r ; } if(i != lowest) { temp = a[lowest] ; a[lowest] = a[i] ; a[i] = temp ; i = lowest ; lowest = 0 ; } }while(i != lowest) ; } long HeapExtractMin() { long nMin = a[1] ; long temp = 0 ; a[1] = a[a[0]] ; a[0]-- ; MinHeapify(1) ; return nMin ; } void HeapInsert(long key) { long nTemp = 0 ; long i = 0 ; a[0]++ ; a[a[0]] = key ; while(i > 1 && a[PARENT(i)] > a[i]) { nTemp = a[i] ; a[i] = a[PARENT(i)] ; a[PARENT(i)] = nTemp ; i = PARENT(i) ; } }
/* ----------------------------------------------------- 先排序,每次找最少数量的两堆合并。再排序,再找最少数量的 两堆 。。。结果超时了。。。 ----------------------------------------------------- */ #include<stdio.h> #define PARENT(i) ((i)/2) #define LEFT(i) (2*(i)) #define RIGHT(i) (2*(i)+1) long a[10004] ; long nHeapSize = 0 ; long nLength = 0 ; long nBegin = 2 ; void MaxHeapify(long i) ; void BuildMaxHeap() ; void HeapSort() ; int main(void) { long n = 0 ; long i = 0 ; long nTotalStrenth = 0 ; long nTemp = 0 ; long nFruitSum = 0 ; scanf("%ld",&n) ; nLength = n ; for(i = 1 ; i <= n ; ++i) { scanf("%ld",&a[i]) ; } HeapSort() ; for(i =1 ; i <= n-1 ; ++i) { a[i+1] += a[i] ; nFruitSum = a[i+1] ; nTotalStrenth += nFruitSum ; a[i]= 0 ; if(i < n-2 && nFruitSum > a[i+2]) { nBegin = i+1 ; HeapSort() ; } } if(1 == n) nTotalStrenth = a[1] ; printf("%ld\n",nTotalStrenth) ; return 0 ; } void MaxHeapify(long i) { long l = LEFT(i) ; long r = RIGHT(i) ; long largest = 0 ; long temp = 0 ; while(i != largest) { if(l <= nHeapSize && a[l] > a[i]) { largest = l ; } else { largest = i ; } if(r <= nHeapSize && a[r] > a[largest]) { largest = r ; } if(i != largest) { temp = a[largest] ; a[largest] = a[i] ; a[i] = temp ; MaxHeapify(largest) ; } } } void BuildMaxHeap() { nHeapSize = nLength ; long i = 0 ; for(i = nLength/2 ; i >= 1 ; --i) { MaxHeapify(i) ; } } void HeapSort() { long i = 0 ; long nTemp = 0 ; BuildMaxHeap() ; for(i = nLength ; i >= nBegin ; --i) { nTemp = a[1] ; a[1] = a[i] ; a[i] = nTemp ; nHeapSize-- ; MaxHeapify(1) ; } }
相关文章推荐
- [ACM_HDU_2037]今年暑假不AC(贪心算法)
- 杭电ACM 今年暑假不AC 2037(关于最简单的贪心算法)
- 树-堆结构练习——合并果子之哈夫曼树
- SDUTOJ 2127 树-堆结构练习——合并果子之哈夫曼树
- ACM 75. [NOIP2004] 合并果子(水贪心)
- 树-堆结构练习——合并果子之哈夫曼树
- 树-堆结构练习---合并果子之哈夫曼树
- 树-堆结构练习——合并果子之哈夫曼树oj
- 树-堆结构练习——合并果子之哈夫曼树
- A - 树-堆结构练习——合并果子之哈夫曼树
- 树-堆结构练习——合并果子之哈夫曼树
- 洛谷luogu-1090 合并果子(2004NOIp提高组) HQG_AC的博客
- 树-堆结构练习——合并果子之哈夫曼树
- ACM水题-Rescue LK(AC,迷宫问题,DFS求解)
- SDUT 2127 树-堆结构练习——合并果子之哈夫曼树
- 树-堆结构练习——合并果子之哈夫曼树---3401
- 树-堆结构练习——合并果子之哈夫曼树
- sdutacm-树-堆结构练习——合并果子之哈夫曼树
- 树-堆结构练习——合并果子之哈夫曼树(STL)
- 树-堆结构练习——合并果子之哈夫曼树(其实是优先队列)