Cod sursa(job #374138)

Utilizator stocarulCosmin-Mihai Tutunaru stocarul Data 16 decembrie 2009 02:17:17
Problema Coduri Huffman Scor 100
Compilator c Status done
Runda Arhiva educationala Marime 2.1 kb
#include<stdio.h>
#define infile "huffman.in"
#define outfile "huffman.out"
#define nmax (1000*1001)
#define bmax 63
struct nod
{
	long long val; //valoarea din acest nod
	int lg; //lungimea de la radacina pana la el
	int t; //tatal nodului
	char b; //tipul bitului (adica daca e de dreapta sau de stanga "=))'" )
	int st,dr; //adresa catre cei 2 fii
} n[2*nmax]; //informatiile arborelui ce se formeaza
long long b[bmax]; //b[i]=2^i
int m; //numarul de noduri
int rad; //radacina arborelui
long long lg; //lungimea noului text

inline void unit(int i, int j, int k)
{ //uneste nodurile i si j in nodul k
	n[k].val=n[i].val+n[j].val;
	n[k].st=i; n[k].dr=j;
}

inline int min(int *st1, int dr1, int *st2, int dr2)
{ //valoarea minima  dintre cele doua cozi
	if(*st1<=dr1 && (*st2>dr2 || n[*st1].val<=n[*st2].val)) { *st1+=1; return *st1-1; }
	*st2+=1; return *st2-1;
}

long long numar(int x)
{ //numarul ce-l formeaza aceasta frunza
	long long nr=0;
	int h;
	for(h=0;x;x=n[x].t,h++)
		if(n[x].b)
			nr+=b[h];
	return nr;
}

void read()
{
	int i;
	scanf("%d\n",&m);
	for(i=1;i<=m;i++)
		scanf("%lld\n",&n[i].val);
}

void init()
{
	int st1=3,dr1=m; //capetele primei cozi
	int st2=m+1,dr2=m+1; //capetele celeilalte cozi
	int i;
	
	//initializam coada 2
	unit(1,2,st2);
	
	//transformam padurea intr-un arbore huffman
	while(st1<=dr1 || st2<dr2)
		unit(min(&st1,dr1,&st2,dr2),min(&st1,dr1,&st2,dr2),dr2+1),dr2++;
	
	//salvam radacina arborelui
	rad=dr2;
	
	//construim vectorul b
	for(b[0]=i=1;i<bmax;i++)
		b[i]=2*b[i-1];
}

void dfs(int rad, int lg)
{
	n[rad].lg=lg;
	if(n[rad].st) n[n[rad].st].t=rad,dfs(n[rad].st,lg+1);
	if(n[rad].dr) n[n[rad].dr].t=rad,n[n[rad].dr].b=1,dfs(n[rad].dr,lg+1);
}

void solve()
{
	int i;
	
	//calculam lungimea totala a textului
	for(i=1;i<=m;i++)
		lg+=n[i].val*n[i].lg;
}

void write()
{
	int i;
	
	//lungimea noului text
	printf("%lld\n",lg);
	
	//afisem informatiile fiecarui caracter
	for(i=1;i<=m;i++)
		printf("%d %lld\n",n[i].lg,numar(i));
}

int main()
{
	freopen(infile,"r",stdin);
	freopen(outfile,"w",stdout);
	
	read();
	init();
	dfs(rad,0);
	solve();
	write();
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}