PTA 7-1 修理牧場

題目描述

農夫要修理牧場的一段柵欄,他測量了柵欄,發現需要N塊木頭,每塊木頭長度爲整數L​i個長度單位,於是他購買了一條很長的、能鋸成N塊的木頭,即該木頭的長度是L​i的總和。
但是農夫自己沒有鋸子,請人鋸木的酬金跟這段木頭的長度成正比。爲簡單起見,不妨就設酬金等於所鋸木頭的長度。例如,要將長度爲20的木頭鋸成長度爲8、7和5的三段,第一次鋸木頭花費20,將木頭鋸成12和8;第二次鋸木頭花費12,將長度爲12的木頭鋸成7和5,總花費爲32。如果第一次將木頭鋸成15和5,則第二次鋸木頭花費15,總花費爲35(大於32)。
請編寫程序幫助農夫計算將木頭鋸成N塊的最少花費。

輸入格式:

輸入首先給出正整數N(≤10000),表示要將木頭鋸成N塊。第二行給出N個正整數(≤50),表示每段木塊的長度。

輸出格式:

輸出一個整數,即將木頭鋸成N塊的最少花費。

輸入樣例:

8
4 5 1 2 1 3 1 1

輸出樣例:

49

思路分析

第一種思路(運行超時)

先寫個排序算法,對輸入數組進行排序,然後選取最小的兩個數進行相加,然後把這個數在數組裏面刪除,把得到的結果加進去,在循環以上操作,直到數組裏面只有一個數退出。最終結果爲每一次得到的結果的累加值。

#include <stdio.h>
#include<stdbool.h>
void sort(int a[],int n){
    int i, j, temp;
    for(i=0; i<n-1; i++){
        for(j=i+1; j<n; j++){
            if(a[i] > a[j]){
                temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }
}
int main() { 
	int a[10001];
	int n,i,sum=0,temp=0;
	scanf("%d",&n);
	for (i = 0; i < n; i++) {
	    scanf("%d",&a[i]);
	}
	if(n==1)
	    printf("%d\n",0);
	else if(n==2)
	    printf("%d\n",a[0]+a[1]);
	else{
    	while(true){
    	    sort(a,n);
    	    if(a[n-2]==0)
    	        break;
    	    for (i = 0; i < n; i++) {
    	        if(a[i]!=0){
    	            temp=a[i]+a[i+1];
    	            a[i]=0;a[i+1]=temp;
    	            sum+=temp;
    	            break;
    	        }
    	    }
    	}
    	printf("%d\n",sum);
	}
	return 0;
}


在這裏插入圖片描述

第二種思路(來源於百度)

可以用哈弗曼樹解決這個問題,先將輸入的數都申請爲內存節點(樹),找到輸入的最小的數和次小的數的下標,然後建立父節點,值爲他們的和。把最小的數對應的下標的樹變成NULL,次小的數對應的下標的樹變成父節點(父樹),然後循環上面的操作。最後求得所有非葉節點的和,可以由所有葉節點深度和權值的乘機之和求出。原文鏈接
這種算法比上面的算法時間複雜度要低,可以過PTA的檢測,因爲在尋找最小的兩個值時,第一種思路是排序而第二種思路是找到最小的下標,會少一層循環。

#include<stdio.h>
#include<stdlib.h> 
typedef int ElemType;  
typedef struct HuffmanTreeNode{  
    ElemType data;  //哈夫曼樹中節點的權值
    struct HuffmanTreeNode* left;  
    struct HuffmanTreeNode* right;  
}HuffmanTreeNode,*PtrHuffman; 
PtrHuffman createHuffmanTree(ElemType arr[],int max){
    PtrHuffman ptrArr[max];
    PtrHuffman ptr,pRoot=NULL;  

    for (int i = 0; i < max; i++){  //初始化結構體指針數組,數組中每一個元素爲一個結構體指針類型
        ptr = (PtrHuffman)malloc(sizeof(HuffmanTreeNode));  
        ptr->data = arr[i];  
        ptr->left = ptr->right = NULL; 
        ptrArr[i] = ptr;
    }
    
    for(int i = 1; i < max; i++)
	{  //進行 n-1 次循環建立哈夫曼樹  
        //k1表示森林中具有最小權值的樹根結點的下標,k2爲次最小的下標
        int k1 = -1, k2;
        for(int j = 0; j < max; j++){  
            if (ptrArr[j] != NULL && k1 == -1){  
                k1 = j;  
                continue;  
            }  
            if (ptrArr[j] != NULL){  
                k2 = j;  
                break;  
            }  
        }  
        //將指針數組中的指針指向的最小值賦值給索引號爲k1的,次小值賦值給索引號爲k2的
        for (int j = k2; j < max; j++){
            if(ptrArr[j] != NULL){
                if(ptrArr[j]->data < ptrArr[k1]->data){
                    k2 = k1;
                    k1 = j;
                }else if(ptrArr[j]->data < ptrArr[k2]->data){
                    k2 = j;
                }
            }
        }
        //由最小權值樹和次最小權值樹建立一棵新樹,pRoot指向樹根結點
        pRoot = (PtrHuffman)malloc(sizeof(HuffmanTreeNode));
        pRoot->data = ptrArr[k1]->data + ptrArr[k2]->data;
        pRoot->left = ptrArr[k1];
        pRoot->right = ptrArr[k2];

        ptrArr[k1] = pRoot; //將指向新樹的指針賦給ptrArr指針數組中k1位置
        ptrArr[k2] = NULL; //k2位置爲空
    }

    return pRoot;
}
ElemType calculateWeightLength(PtrHuffman ptrTree,int len){
    if(ptrTree==NULL){ //空樹返回0
        return 0;
    }else{
        if(ptrTree->left==NULL && ptrTree->right==NULL){ //訪問到葉子節點
            return ptrTree->data * len;
        }else{
            return calculateWeightLength(ptrTree->left,len+1) + calculateWeightLength(ptrTree->right,len+1); //向下遞歸計算
        }
    }
}
int main(){
    ElemType arr[10001];
    int max;
    scanf("%d",&max);
    int i=0;
    while(i<max)
    scanf("%d",&arr[i++]);
    PtrHuffman pRoot = createHuffmanTree(arr,max);  //返回指向哈夫曼樹根節點的指針

    printf("%d",calculateWeightLength(pRoot,0));
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章