题目大意
你希望得到n个长分别为 a1,a2,a3......an 的木板,给你一个长木板长为 a1+a2+a3......+an 你可以通过切n-1刀得到你想要的n个木板,但每切一刀有个代价,需要花费和所切木板长度数量相同的金钱,问最少需要花费多少金钱?
分析
不管怎么分最后都要分成n分,而每次分都是把一个节点分成两个,所以可以看出这是一个二叉树问题,叶节点就是
a1,a2,a3......an
。仔细观察后发现,由某个叶节点所引起的花费是: 叶节点权值(长度)*该节点深度(到达该节点所经过的切割数)。求所有节点带权路径长度和最小问题,也就是哈夫曼树。
对于这道题,最后把除了根节点以外的所有节点的权值加起来就是答案了,这等价于 sum(叶节点权值*叶节点深度)。
胡乱写的一个哈夫曼,结构体里的deep没用到。第一发wa改成long long int后过了。
代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
const int INF=999999999;
int n;
int a[20005];
struct HTnode
{
int pa;
int lchild,rchild;
long long int w;
int deep;
int pos;
friend bool operator<(HTnode a,HTnode b)
{
return a.w>b.w;
}
}HT[50000];
int nodecount=0;
priority_queue<HTnode> Q;
void Init_Huffman_Tree()
{
for(int i=1;i<=n;i++)
{
struct HTnode *ptr=&HT[++nodecount];
ptr->deep=0;
ptr->lchild=0;
ptr->pa=0;
ptr->rchild=0;
ptr->w=a[i];
ptr->pos=nodecount;
Q.push(*ptr);
}
}
void Huffman_Tree()
{
while(1)
{
HTnode node1;
HTnode node2;
node1=Q.top();Q.pop();
if(Q.empty())break;
node2=Q.top();Q.pop();
int pos1=node1.pos;
int pos2=node2.pos;
HT[pos1].pa=nodecount;
HT[pos2].pa=nodecount;
HT[++nodecount].lchild=pos1;
HT[nodecount].rchild=pos2;
HT[nodecount].pos=nodecount;
HT[nodecount].pa=0;
HT[nodecount].w=HT[pos1].w+HT[pos2].w;
Q.push(HT[nodecount]);
}
}
/*
void Bianli(int pos)
{
int pos1=HT[pos].lchild;
if(pos1!=0)
{
HT[pos1].deep=HT[pos].deep+1;
Bianli(pos1);
}
int pos2=HT[pos].rchild;
if(pos2!=0)
{
HT[pos2].deep=HT[pos].deep+1;
Bianli(pos2);
}
}*/
int main()
{
while(scanf("%d",&n)!=EOF)
{
nodecount=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
Init_Huffman_Tree();
Huffman_Tree();
/*
for(int i=1;i<=nodecount;i++)
{
if(HT[i].pa==0){HT[i].deep=0;Bianli(i);}
break;
}*/
long long int ans=0;
for(int i=1;i<=nodecount;i++)
{
if(HT[i].pa!=0){ans+=HT[i].w;}
}
cout<<ans<<endl;
}
}
/*
3
8
5
8
*/