07-Fence Repair-boj

背景:一个农场主要修篱笆,需要N段木头(1<= N <= 1000),每段木头长度不同( 1<= L <= 50000)。现在他有一颗长度恰好合适的树干,去找人锯成N段。每锯一次收费为当前长度总和。

例如: 需要3段木头,每段长为8、 5 、8 。第一次据的时候总长度为8+5+8 = 21,收费21 ,假设锯为8 和13 两段,再将13那一段剧为5和8,收费13。总收费为34

问题:求该农场主锯完木头的最低收费是多少。


分析:

这个题,反过来想,N段木头的数组,每次找两个最小的段数组,组合后放入原队列,继续组合。其实就是哈夫曼树。但是我想不出怎么证明。

        编程需要一个最小优先队列,以每次从队列中取出最小的两个数,把组合的新数入队。我使用最小堆实现的。代码如下:

       

#include <iostream>

using namespace std;
//鍫嗕繚鎸侊紝arr[0]涓哄爢闀垮害銆?
void  Minheapify( int * arr , int i)
{
    if(arr == NULL || arr[0] <= 0  || arr[0] < i )
    {
	return;
    }

    int left = 2*i;
    int right = 2*i + 1;
    
    int minIndex = i;

    if( left <= arr[0] && arr[left] < arr[minIndex] )
    {
	minIndex = left;
    }
    
    if( right <= arr[0] && arr[right] < arr[minIndex] )
    {
	minIndex = right;
    }
    
    if( minIndex != i )
    {
	int temp = arr[minIndex];
	arr[minIndex] = arr[i];
	arr[i] = temp;
	
	Minheapify( arr , minIndex );
    }
}

void BuildHeap( int * arr )
{
    if( arr == NULL || arr[0] <= 0 )
	return;
    
    int len = arr[0];
    for( int i = len/2 + 1 ; i >0 ; i-- )
    {
	Minheapify( arr , i );
    }
}


int HeapExtractMin( int * arr )
{
    if( arr == NULL || arr[0] <= 0 )
	return -1;
    
    int min = arr[1];
    
    arr[1] = arr[ arr[0] ];
    arr[0] -= 1;
    Minheapify( arr , 1 );

    return min;
}

void HeapDecreaseKey( int * arr , int i ,int key )
{
    if( arr == NULL || arr[0] <= 0 || i > arr[0] )
	return;
    
    //涓嶅厑璁稿鍔?
    if( key > arr[i] )
	return;
    
    arr[i] = key;
    while( i > 1 && arr[i/2] > arr[i] )
    {
	int temp  = arr[i/2];
	arr[i/2] = arr[i];
	arr[i] = temp;
	
	i = i/2;
    }
}

void  MinHeapInsert( int * arr , int key )
{
    if( arr == NULL || arr[0] <= 0 )
	return ;
    
    arr[0] += 1;
    arr[ arr[0] ] = key + 1;
    HeapDecreaseKey( arr , arr[0] , key  );
}


void Print( int * arr )
{
    if( arr == NULL || arr[0] <= 0 )
	return;
    for( int i = 1; i <= arr[0] ; i++ )
	cout<<arr[i];
    cout<<endl;
}
int main()
{
    int n = 0;
    int arr[1024];
    while( cin>>n )
    {
	arr[0] = n;
	for( int i = 1; i <= n; i++ )
	    cin>>arr[i];
	
	BuildHeap( arr );
	
	int sum = 0;
	//Print( arr );
        while( arr[0] > 1 )
	{
	    int top1 = HeapExtractMin( arr );
	   // Print( arr );
	    int top2 = HeapExtractMin( arr );
	   // Print( arr);
	   
	    int newElement = top1 + top2;
	    sum += newElement;
	    MinHeapInsert( arr , newElement );
	   // Print( arr);
	}
	cout<< sum<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值