ACM水题-合并果子(堆结构,贪心算法,AC)

合并果子

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) ;
	}
}

 

    原文作者:贪心算法
    原文地址: https://blog.csdn.net/gzzheyi/article/details/7555097
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞