[哈夫曼树] Jzoj P1736 扑克游戏

Description

  有一棵无穷大的满二叉树,根为star,其余所有点的权值为点到根的距离,如图:
  
  现在你有一些扑克牌,点数从1到13,你要把这些扑克牌全部放到这个树上:
  1. 当你把点数为i的扑克牌放在权值为j的点上,那么你会得到i*j的分数。
  2. 当你把一个扑克牌放在一个节点上,那么你就不能把别的扑克牌放在这个节点以及这个节点的子树上。
  你的目标是最小化你的得分。
 

Input

  文件名为 poker.in
  输入第一行为一个数字N,表示你有的扑克牌数;
  接下来一行N个数字,数字在1到13之间。

Output

  文件名为 poker.out
  一个数字,最小得分。
 

Sample Input

3
5 10 13

Sample Output

43
 

Data Constraint

 
 

Hint

【样例说明】
  
【数据范围】
  30%数据 N<=100
  100%数据满足1<=N<=10000.

 

 

题解

  • 典型哈夫曼树的结构
  • 每次找两个跳,再将其和加入树
  • 记录跳出去的和

代码

 1 #include<iostream>
 2 #include<iostream>
 3 #include<cstdio>
 4 #define INF 2147483647
 5 #define N 20000
 6 using namespace std;
 7 long long dui[N*2+1],top;
 8 void add(long x)
 9 {   
10     long now;
11     dui[++top]=x;
12     for (now=top;dui[now/2]>dui[now]&&now>1;now/=2) swap(dui[now],dui[now/2]);
13 }
14 long sum()
15 {   
16     long ans=dui[1],now;
17     bool t=false;
18     dui[1]=INF; now=1;
19     while (!t)
20     {
21         t=true;
22         if (now*2==top||dui[now*2]<dui[now*2+1])
23         {
24             if (dui[now]>dui[now*2])
25             {
26                 swap(dui[now],dui[now*2]);
27                 now=now*2;
28                 t=false;
29             }
30         }
31         else 
32             if (now*2+1<=top)
33                 if (dui[now]>dui[now*2+1])
34                 {
35                     swap(dui[now],dui[now*2+1]);
36                     now=now*2+1;
37                     t=false;
38                 }
39     }
40     return ans;
41 }
42 
43 int main()
44 {   
45     long n,m,x;
46     long long ans=0;
47     scanf("%ld",&n);
48     for (int i=1;i<=n;i++)
49     {
50         scanf("%ld",&x);
51         add(x);
52     }
53     for (int i=1;i<n;i++)
54     {
55         x=sum()+sum();
56         ans+=x;
57         add(x);
58     }
59     printf("%lld\n",ans);
60     return 0;
61 }

 

posted @ 2018-07-06 15:36  BEYang_Z  阅读(253)  评论(0编辑  收藏  举报