多元Huffman编码变形
时间限制(普通/Java) :
1000 MS/ 3000 MS 运行内存限制 : 65536 KByte
总提交 : 14 测试通过 : 6
总提交 : 14 测试通过 : 6
比赛描述
在一个操场的四周摆放着n 堆石子。现要将石子有次序地合并成一堆。规定在合并过程中最多可以有m(k)次选k 堆石子合并成新的一堆,2≤k≤n,合并的费用为新的一堆的石子数。试设计一个算法,计算出将n 堆石子合并成一堆的最小总费用。
对于给定n堆石子,编程计算合并成一堆的最小总费用。
输入
文件的第1 行有1 个正整数n,表示有n 堆石子。第2行有n个数,分别表示每堆石子的个数。第3行有n-1 个数,分别表示m(k)(2≤k≤n)的值。
输出
程序运行结束时,将计算出的最小总费用输出,问题无解时输出“Nosolution!”
样例输入
7
45 13 12 16 9 5 22
3 3 0 2 1 0
样例输出
136
提示
undefined
题目来源
NUAA
#include<iostream>
using namespace std;
int n,*a,*b,*m;
//堆根标号为1
void minHeapAdjust(int *a, int i, int n){
int child = i<<1;
while(child<=n){
if(child+1<=n && a[child+1]<a[child]){
child++;
}
if(a[i]>a[child]){
swap(a[i],a[child]);
}else{
break;
}
i = child;
child = i<<1;
}
}
//前 i 堆
bool search(int i,int sum){
int j;
if(i==1){
if(sum==0){
return 1;
}else{
return 0;
}
}
for(j=m[i];j>=0;j--){
b[i] = j;
if(sum-b[i]*(i-1)<0){
continue;
}
if(search(i-1,sum-b[i]*(i-1))){
return 1;
}
}
return 0;
}
int main(){
// freopen("test.txt","r",stdin);
int i,j,k;
scanf("%d",&n);
a = new int[n+1]; //第 i 堆石子的个数为a[i]
b = new int[n+1]; // i 堆石子进行合并成一堆,采用了b[i]次
m = new int[n+1]; // i 堆石子进行合并成一堆,最多可采用m[i]次
for(i=1;i<=n;i++){
scanf("%d",a+i);
}
for(i=2;i<=n;i++){
scanf("%d",m+i);
}
if(search(n,n-1)){
// for(i=2;i<=n;i++){
// printf("b[%d] = %d\n",i,b[i]);
// }
for(i=n;i>=1;i--){
minHeapAdjust(a,i,n);
}
int cost=0, num, heapSize=n;
for(i=2;i<=n;i++){ //i堆石子合并b[i]次
for(j=0;j<b[i];j++){
num = 0;
for(k=0;k<i-1;k++){
num += a[1];
a[1] = a[heapSize--];
minHeapAdjust(a,1,heapSize);
}
num += a[1]; //最后要插入num
a[1] = num;
minHeapAdjust(a,1,heapSize);
cost += num;
}
}
printf("%d\n",cost);
}else{
printf("No solution!\n");
}
}