【鸿雁传书】第四次OJ的总结

版权声明:转载请注明出处 https://blog.csdn.net/weixin_41238584/article/details/83660519

神tm鸿雁传书

2018/11/2

问题描述

随着科技的发展,通信的手段日新月异。然而不得不说,至今都没有比鸿雁传书更为深情浪漫的通信方式出现。

两个迷恋地球文明&中华文化的【三体人】出于浪漫主义需求,决定以后通过鸿雁传书的方式来进行通信。为了方便起见,我们姑且叫他们大刘大白。鸿雁传书,情真意切,大刘和大白的感情也一日比一日深厚。

Fig.1 图文无关

两人的私密通信,自然是“不足为外人道”的。为此大刘煞费苦心地设计了一套用01比特来表示每个三体文字的方式,称为“鸿雁传书字典”。其巧妙之处在于,任何一个01比特串都不会是其他串的前缀串。于是收到一大堆01比特的大白对照着“鸿雁传书字典”,就能原样知道大刘想写的是什么三体文字了。而别人手中没有这个字典,自然不知道这些比特的含义。一个非常简单的(只包含四个可选三体文字)例子Fig.2所示。

Fig.2 合法的“鸿雁传书字典”及其传书过程示例

好景不长,由于三体文字实在是博大精深,有成千上万个。原本的“鸿雁传书字典”是大刘随手设计的,每个三体字都要用好多好多比特来描述。大刘有一次问大白“你吃了没”竟然用了23333个比特,写了一大叠纸,鸿雁送到一半累得吐血掉进黑暗森林再没飞起来。

Fig.3 累得掉进黑暗森林的鸿雁(注意这是三体的鸿雁,长得像鸽子是可以理解的)

大白得知后伤心地哭了很久(●—●),大刘也十分难过。他和大白保证会设计出新的、最好的“鸿雁传书字典”,为此他把自己和大白的所有传书都搜集了起来,并统计出了其中每一个三体文字的出现次数

做完这一切后,大刘对着这个统计表犯了难,该怎么设计出一个最好的“鸿雁传书字典”,使得平均意义上表示一个三体文字需要的比特数最少呢?你能帮帮大刘么?

输入格式

输入共有 N+1 行。

第 1 行包含一个整数N,代表大刘统计出的不同三体文字的数量。

第 2 行到第 N+1 行每行有一个整数,代表大刘统计的所有书信里,这行对应的三体文字出现的总次数。

注意:

1. 大刘为了请你帮忙,已经把所有三体字按照【1体】-【2体】-【3体】- …… -【N体】的顺序进行了排列,也即第 k 行代表 “【k-1体】” 这个字出现的总次数。

2. N不超过300,000。

输出格式

输出共有 N+1 行。

第 1 行包含一个浮点数F,代表你设计的最优“鸿雁传书字典”中,表示每个三体字需要的平均比特数保留6位小数

第 2 行到第 N+1 行每行有一个“01”比特串,代表你设计的最优“鸿雁传书字典”中,表示这行对应三体字的01比特编码。

注意:

1. 输出“鸿雁传书字典”中编码方案的时候,必须也按照【1体】-【2体】-【3体】- …… -【N体】的顺序进行输出,也即和输入文件中的顺序匹配

2. 表示“鸿雁传书字典”中的编码方案必须使用“0”和“1”来表示,例如“0101”。不接受别的等价描述,例如“2323”。

3. 严格保证输出是N+1行,并且每行中不能有和编码比特无关的空格或其他字符

输入样例

5
2
1
2
2
3

输出样例

2.300000
111
110
01
00
10
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;

typedef struct HTNode {
	HTNode * lch, *rch, *father;
	long long int weight;
	long long int order;
	HTNode() :lch(NULL), rch(NULL),father(NULL){}
}HTNode, *HuffmanTree;

typedef char **HuffmanCode;

void createCode(HTNode ** leave, HuffmanCode &HC, long long int n) {
	HC = (HuffmanCode)malloc(n * sizeof(char *));
	char * code = new char[n];
	code[n - 1] = '\0';
	long long int i;
	for (i = 0; i < n; i++)
	{
		HTNode * current = leave[i];
		HTNode * father =current->father;
		long long int start = n - 1;
		while (father != NULL)
		{
			if (father->lch == current)
				code[--start] = '0';
			else
				code[--start] = '1';
			current = father;
			father = current->father;
		}

		HC[i] = (char *)malloc((n - start) * sizeof(char));
		strcpy(HC[i], code + start);
	}
	delete code;
}
struct cmp {
	bool operator() (HTNode *a, HTNode * b) {
		return (a->weight > b->weight);
	}
};
priority_queue < HTNode*, vector<HTNode*>, cmp > pque;

void createTree() {
	while (pque.size() != 1) {
		HTNode *a, *b;
		a = pque.top();
		pque.pop();
		b = pque.top();
		pque.pop();
		HTNode * temp = new HTNode;
		a->father = temp;
		b->father = temp;
		temp->weight = a->weight + b->weight;
		temp->lch = a;
		temp->rch = b;
		pque.push(temp);
	}
}

int main() {
	long long int Num, i;
	scanf("%lld", &Num);
	long long int * Freq = (long long int)malloc(Num * sizeof(long long int));
	for (i = 0; i < Num; ++i)	scanf("%lld", &Freq[i]);
	HTNode ** Leave = (HTNode **)malloc(Num * sizeof(HTNode *));
	for(i=0;i<Num;++i)	Leave[i] = (HTNode *)malloc(sizeof(HTNode));
	for (i = 0; i < Num; ++i) {
		Leave[i]->weight = Freq[i];
		pque.push(Leave[i]);
	}
	createTree();

	HuffmanCode Code;
	createCode(Leave, Code, Num);

	long long int sum1 = 0;
	long long int sum2 = 0;
	float average;
	for (i = 0; i < Num; ++i) {
		sum1 += strlen(Code[i]) * Freq[i];
		sum2 += Freq[i];
	}
	average = (float)sum1 / sum2;

	if (Num == 1) {
		average = 1;
		strcpy(Code[0], "0");
	}

	printf("%.6f\n", average);
	for (i = 0; i < Num; ++i)
		printf("%s\n", Code[i]);

        free(Freq);
	for (i = 0; i < Num; ++i)	free(Leave[i]);
	free(Leave);
	for (i = 0; i < Num; ++i)	free(Code[i]);
	free(Code);
	return 0;
}

我直接用的STL里的优先级队列,遍历哈夫曼树生成编码那块出于无奈(OJ的最后几个数据量过大)把原本递归方法改写了,虽然丑但是内存少……

算法问题还是另外找时间总结。

猜你喜欢

转载自blog.csdn.net/weixin_41238584/article/details/83660519