题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47668
题解:
//思路就是先把二叉树补全,从最下层开始给叶子节点赋值,每一层的叶子节点能取到的最小值为下一层中的最大值
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,top;
typedef struct Huffman
{
int dis;
long long l;
bool flag;
}H;
H HT[200];
bool cmp(const H &a,const H &b)
{
return a.dis>b.dis;
}
bool cmp2(const H &a,const H &b)
{
return a.l<b.l;
}
long long getAns()
{
top=n;
int s=0,index;
/**************************
以下代码是为了补全非叶子节点使其构成完整的二叉树
****************************/
while(top-s>1)
{
int cnt=0;
for(int i=s;i<top;i++)
{
if(!cnt)
cnt++;
else if(HT[i].dis==HT[i-1].dis)
cnt++;
else
break;
}
s+=cnt;
index=s;
while(cnt>0)
{
for(int i=top;i>index;i--)
HT[i]=HT[i-1];
HT[index].dis=HT[s-1].dis-1;
HT[index].flag=false;
index++;
top++;
cnt-=2;
}
}
/***************************************/
s=0;
while(top-s>1)
{
int c=0;
for(int i=s;i<top;i++)
{
if(HT[i].dis==HT[0].dis)
{
c++;
HT[i].l=1;
continue;
}
if(c==0)
c++;
else if(HT[i].dis==HT[i-1].dis)
c++;
else
break;
}
sort(HT+s,HT+s+c,cmp2);//因为最优二叉树中每个非叶子节点都是下一层中值最小的两个结点之和,所以应该先把下层的结点排个序
int cc=0;
for(int i=s+c;i<top;i++)
{
if(cc==0)
cc++;
else if(HT[i].dis==HT[i-1].dis)
cc++;
else
break;
}
int temp=0,t=0;
long long Max=-1;//Max用来记录每层的最大值
for(int i=s+c;i<s+c+cc;i++)
{
if(!HT[i].flag)
{
HT[i].l=HT[s+temp].l+HT[s+temp+1].l;
if(Max<HT[s+temp].l)
Max=HT[s+temp].l;
if(Max<HT[s+temp+1].l)
Max=HT[s+temp+1].l;
temp+=2;
}
}
for(int i=s+c;i<s+c+cc;i++)
{
if(HT[i].flag)
HT[i].l=Max;//叶子节点均赋值为下一层的最大值
}
s=s+c;
}
long long ans=0;
for(int i=0;i<top;i++)
if(HT[i].flag)
ans+=HT[i].l;
return ans;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d",&HT[i].dis);
HT[i].flag=true;
}
sort(HT,HT+n,cmp);
printf("%lld\n",getAns());
}
return 0;
}