题要求k阶哈夫曼树的深度和编码总长,输入是各单词的出现频次,样例包含一个等长编码最优解,另一个是哈夫曼编码最优解。之前int compare里longlong作差溢出45pts改了之后还是65pts,查了一下longlong x int会隐式转换类型为long long所以应该没毛病。难道是算法的问题?我和题解的方法除了最后遍历不一样(题解是一边建树一边遍历),可是我的遍历也看不出问题在哪。
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<math.h>
#include<limits.h>
#include<float.h>
#include<ctype.h>
#define swap(x,y) temp=x,x=y,y=temp
#define LL long long
int n,k;
typedef struct Node{
int son[10],s;//s记录儿子个数
LL w;
}Node;
Node node[210000];//最多需要两倍节点(二叉的时候)
int heap[100010],hi;//堆对节点角标排序
int maxd,eql;//两种算法的单个单词最长编码长度
LL ans,greedy;//两种算法的最终长度
int compare1(const void *x,const void *y)
{LL temp=((Node*)x)->w-((Node*)y)->w;return temp>0?1:(temp?-1:0);}//qsort非要int返回值的函数
bool compare2(const int x,const int y)
{return node[heap[x]].w<node[heap[y]].w;}
void ascend(int i)//堆上浮
{
int fa=i/2,temp;
if(fa&&compare2(i,fa)){
swap(heap[i],heap[fa]);
ascend(fa);
}
}
void sink(int i)//堆下沉
{
int mini=i,temp;
if(i*2<hi&&compare2(i*2,mini))mini=i*2;
if(i*2+1<hi&&compare2(i*2+1,mini))mini=i*2+1;
if(mini!=i){
swap(heap[i],heap[mini]);
sink(mini);
}
}
void inherit()//pop一个节点编号,加入在建的node[n]
{
node[n].son[node[n].s++]=heap[1],
node[n].w+=node[heap[1]].w;
heap[1]=0,heap[1]=heap[--hi];
sink(1);
}
void add()//在堆末尾加入node[n]
{
heap[hi]=n;
ascend(hi);
hi++,n++;
}
void traverse(int i,int degree)//遍历哈夫曼树
{
if(degree>maxd)maxd=degree;
if(!node[i].s)ans+=node[i].w*degree;
else{
int j;
for(j=0;j<node[i].s;j++)
traverse(node[i].son[j],degree+1);
}
}
int main()
{
int i;
scanf("%d%d",&n,&k);
for(eql=1;pow((double)k,(double)eql)<n;eql++);//算一下等长编码,单个单词要多长
for(i=1;i<=n;i++)
{
scanf("%lld",&node[i].w);//每个单词的出现频次
greedy+=node[i].w*eql;//等长编码的总长结果,好像也不算贪心
}
while((n-1)%(k-1)!=0)n++;//补充空节点好让哈夫曼树建完整,避免浪费根节点的儿子空位
qsort(node+1,n,sizeof(Node),compare1);
for(i=1;i<=n;i++)heap[i]=i;//堆初始化
n=hi=n+1;
while(hi>2)//每次取堆顶k个节点加入在建的node[n]
{
for(i=1;i<=k;i++)
inherit();
add();
}
for(i=0;i<node[heap[1]].s;i++)//遍历根节点的所有儿子
traverse(node[heap[1]].son[i],1);
if(ans==greedy)
printf("%lld\n%d\n",ans,maxd<eql?maxd:eql);
else if(ans<greedy)
printf("%lld\n%d\n",ans,maxd);
else
printf("%lld\n%d\n",greedy,eql);
return 0;
}