多元Huffman編碼變形—回溯法
阿新 • • 發佈:2020-11-27
一、問題描述
描述
在一個操場的四周擺放著n堆石子。現要將石子有次序地合併成一堆。規定在合併過程中最多可以有m(k)次選k堆石子合併成新的一堆,2≤k≤n,合併的費用為新的一堆的石子數。試設計一個演算法,計算出將n堆石子合併成一堆的最小總費用。 對於給定n堆石子,計算合併成一堆的最小總費用。
輸入
輸入資料的第1 行有1 個正整數n(n≤100),表示有n 堆石子。第2行有n個數,分別表示每堆石子的個數。第3 行有n-1 個數,分別表示m(k)(2≤k≤n)的值。
輸出Output
將計算出的最小總費用輸出。問題無解時輸出“No solution!”
Sample Input
7 45 13 12 16 9 5 22 3 3 0 2 1 0
Sample Output
136
問題分析
- 首先用分支界限法(回溯法)找出每次合併石子堆數和可用次數
v[i]
- 然後對石子從小到大排序,每次取最小堆數合併石子(這樣保證越往後合併的堆數就越多)
- 這樣就就可以保證最小輸出
程式碼
#include<iostream> #include<algorithm> using namespace std; int n; int p[201]; int m[101]; int v[101]; /** 分支界限法 找出每次合併石子堆數和可用次數 引數:第i次合併,還剩餘sum堆石子 */ bool branch(int i,int sum){ if(i==1){ if(sum==1) return true; else return false; } for(int j=m[i];j>=0;j--){ v[i] = j; if(sum-v[i]*(i-1)<=0){ continue; } if(branch(i-1,sum-v[i]*(i-1))){ return true; } } return false; } /** 把陣列P中的第n-1個數據,插入到i到n-2資料裡, 相當於把i到n從小到大排序 */ void my_sorted(int i){ for (int j = n-1; j >= i; --j) { if(p[j]<p[j-1]){ swap(p[j],p[j-1]); } else break; } } int main(){ cin>>n; for (int i = 0; i < n; ++i) { cin>>p[i]; } for (int i = 2; i <= n; ++i) { cin>>m[i]; } //判斷是否有解,並且把每次需要合併多少堆石子求出來 if(!branch(n,n)){ cout<<"No solution!"<<endl; return 0; } sort(p,p+n); // for(int i=0;i<=n;i++){ // cout<<v[i]<<' '; // } // cout<<endl; int min = 0; int start = 0; int num = n; for (int i = 1; i <= num;i++) { for(int k = 0;k < v[i];k++){ int min2 = 0; for (int j = 0; j < i; ++j) { min2 += p[start++]; } p[n++] = min2; min += min2; my_sorted(start); } } cout<<min<<endl; }