hihocoder #1111 : Huffman编码

来源:互联网 发布:西安天网软件陈一丁 编辑:程序博客网 时间:2024/06/07 22:52

时间限制:30000ms
单点时限:3000ms
内存限制:256MB

描述

给定一个大小为n的字符集Σ中每个字符出现的频数,求不同的Huffman编码的数量模109 + 7。

一个编码是一个从Σ到01字符串的函数。 一个Huffman编码是一个由以下过程生成的编码:

初始时每个字符为一个集合。初始时所有字符对应到空字符串。一个集合S的频数w(S)定义为S内所有字符的频数的和。 不断进行以下操作直到只剩下一个集合:

选择两个不同的集合A和B使得w(A) + w(B)最小。将A内所有字符对应到的字符串前端加上'0'。将B内所有字符对应到的字符串前端加上'1'。添加一个集合C,为A和B的并。删除A和B。

两个编码不同当且仅当存在一个字符对应到的01字符串不同。

输入

第一行,T,测试点个数。下面T个测试点。

对于每个测试点,第一行,n,为字符集Σ的大小。 第二行,n个整数w1, ..., wn. 其中wi为第i个字符的频数。

1 ≤ n ≤ 106. 所有n的和 ≤ 106. 1 ≤ wi ≤ 106.

输出

T行。每行为对应测试点的答案。

样例输入
51121 131 1 141 1 1 141 1 2 2
样例输出
12122424
解题思路

首先统计相同频数出现的次数。这里用map来存储  map[频数]=频数出现次数。

然后从频数小的开始考虑。

1.如果最小频数的出现次数n是偶数。

   则类似于考虑左右字数交换的情况下,n个不同元素进行划分,每块里面都只有2个元素的划分数。比如{1,2,3,4}的不考虑分块内的顺序划分有三种{(1,2),(3,4)},{(1,3),(2,4)},{(1,4),(2,3)},在考虑分块顺序的情况下应该是3*(2^3)。

 依次考虑2个,4个,6个,8个不同元素不考虑顺序的划分,发现存在递推关系。

   比如对于6个元素,先确定(1,2)的话,剩下的4个元素的划分实际上是4个不同元素的划分,然后再依次确定(1,3)、(1,4)、(1,5)、(1,6)的四个元素划分。所以6个元素的划分实际上为(6-1)*(4个不同元素不考虑顺序划分数)。

递推公式为

所以

再考虑每个划分内可以互换位置,则在这种情况下结果是

然后,把map[最小频数]擦除,map[最小频数*2]+=n/2

2.如果最小频数的出现次数n是奇数且大于1

则从里面里面挑出一个单独的,而其他两两组队的清楚共有C(n-1,n)=C(1,n)

此时参与配对的偶数个数可用上面的方法来求。

然后把map[最小频数*2]+=(n-1)/2,map[最小频数]赋值为1。

3.如果最小频数出现次数是1而且map的size为1就结束了。

4如果最小频数出现次数是1,map的size大于1

 就要把改最小频数与第二小频数凑对。凑对共有map[第二小频数]种情况。

然后把map[最小频数+第二小频数]++,map[最小频数]擦除,map[第二小频数]--


源码

// 1111 Huffman编码.cpp : 定义控制台应用程序的入口点。////递归算法#include "stdafx.h"#include <iostream>#include <vector>#include <deque>#include <map>#include <algorithm>using namespace std;const int mode = 1000000007;int same_num_count(int a)    //a为偶数{int b = a - 1;int res = 1;while (b != 1){res = b*res % mode;b = b - 2;}return res;}vector<int> insert_new(vector<int> &w, int a){if (w.size() != 0){int flag = 1;for (int i = 0; i < w.size(); i++){if (w[i]>a){flag = 1;w.insert(w.begin() + i, a);break;}if (w[i] < a)flag = 0;}if (flag==0)w.push_back(a);}elsew.push_back(a);return w;}void comput(vector<int> &w, map<int, int>&count, int &ans){if (count[w[0]] % 2 == 0){ans = ans*same_num_count(count[w[0]]) % mode;ans = ans*pow(2, count[w[0]] / 2);ans = ans%mode;int tmp = 2 * w[0];if (count.find(tmp) == count.end()){ count.insert(pair<int, int>(tmp, count[w[0]] / 2));vector<int>::iterator iter = w.begin();w.erase(iter);w = insert_new(w, tmp);}else{count[tmp] += count[w[0]] / 2;vector<int>::iterator iter = w.begin();w.erase(iter);}//cout << ans << endl;}else if (count[w[0]] % 2 != 0 && count[w[0]] != 1){ans = count[w[0]] * ans * same_num_count(count[w[0]] - 1) % mode;ans = ans * pow(2, (count[w[0]] - 1) / 2);ans = ans%mode;int tmp = 2 * w[0];if (count.find(tmp) == count.end()){count.insert(pair<int, int>(tmp, (count[w[0]] - 1) / 2));w = insert_new(w, tmp);}elsecount[tmp] += (count[w[0]] - 1) / 2;count[w[0]] = 1;//cout << ans << endl;}else{//cout << w.size() << endl;ans = ans * 2 * count[w[1]];ans = ans%mode;count.erase(w[0]);int tmp1 = w[0] + w[1];//cout << tmp1 << endl;vector<int>::iterator iter = w.begin();w.erase(iter);if (count[w[0]] == 1){count.erase(w[0]);iter = w.begin();w.erase(iter);}elsecount[w[0]]--;if (count.find(tmp1) == count.end()){count.insert(pair<int, int>(tmp1, 1));w = insert_new(w, tmp1);}elsecount[tmp1]++;//cout << w.size() << endl;//cout << ans << endl;}}int main(){int t;cin >> t;while (t--){int n;cin >> n;vector<int>w;map<int, int>count;for (int i = 1; i <= n; i++){int a;cin >> a;if (count.find(a) == count.end() || count.size() == 0){count.insert(pair<int, int>(a, 1));w.push_back(a);}elsecount[a]++;}sort(w.begin(), w.end());int ans = 1;while (w.size() > 1 || (w.size() == 1 && count[w[0]] != 1))comput(w, count, ans);if (w.size() == 1 && count[w[0]] != 1)ans *= 2;cout << ans << endl;}system("pause");return 0;}


竟然超时了

再改了一下终于过了(scanf和printf有时还蛮有用的)

#include <iostream>#include <vector>#include <map>#include <cstdio>using namespace std;const int mode = 1000000007;int main(){int t;scanf("%d", &t);while (t--){int n;scanf("%d", &n);map<long long, int>count;int a;for (int i = 1; i <= n; i++){scanf("%d", &a);count[a]++;}long long int ans = 1;while (1){map<long long, int>::iterator iter = count.begin();if (iter->second % 2 == 0){long long tmp1 = iter->second;while (tmp1){ans = ans*(tmp1 - 1) * 2 % mode;tmp1 = tmp1 - 2;}long long tmp2 = 2 * iter->first;count[tmp2] += iter->second / 2;count.erase(iter);}else if (iter->second % 2 != 0 && iter->second != 1){ans = iter->second * ans  % mode;int tmp3 = iter->second - 1;while (tmp3){ans = ans*(tmp3 - 1) * 2 % mode;tmp3 = tmp3 - 2;}long long tmp = 2 * iter->first;count[tmp] += (iter->second - 1) / 2;iter->second = 1;}else{if (count.size() == 1)break;long long t = iter->first;count.erase(iter);iter = count.begin();ans = ans * 2 * iter->second%mode;long long tmp1 = t + iter->first;count[tmp1]++;iter->second--;if (iter->second == 0)count.erase(iter);}}printf("%d\n", int(ans));}system("pause");return 0;}

(づ ̄ 3 ̄)づ


1 0
原创粉丝点击