题意:
一棵K叉哈弗曼树,只有中间节点(满儿子)和叶节点两种。给出1-k的连续编码,求出哈弗曼树的结构。
解法:
首先要清楚,哈弗曼编码是一种没有公共前缀的编码,这提供了很重要的剪枝条件
另外,由于树中只含有满节点和空节点(叶子节点),故每分出一个枝条(从叶节点变为一棵子树)至少增加n-1个叶子节点。
利用以上两点,就可以很好的剪枝了。
剪枝判断还是通过字典树(额,这题中似乎叫哈弗曼树比较合适- -)。详细看程序吧。
代码:
1 # include <cstdio>
2 # include <cstring>
3 # include <vector>
4 using namespace std;
5 struct node
6 {
7 node *nxt[20];
8 int count;
9 bool end;
10 node()
11 {
12 memset(nxt,NULL,sizeof(nxt));
13 count=0;
14 end=0;
15 }
16 };
17 int z,n,count,len,c;
18 node buffer[100000];
19 node *head;
20 char str[250];
21 int ans[21];
22 void clear(node *p)
23 {
24 memset(p->nxt,NULL,sizeof(p->nxt));
25 p->end=false;
26 p->count=0;
27 }
28 bool solve(int s,int left,node *p)
29 {
30 if(count>z||p->end) return false;
31 if(s==len&&left==0) return true;
32 else if(left<=0) return false;
33 p->count++;
34 if(p->count==1)
35 {
36 p->end=true;
37 if(solve(s,left-1,head))
38 {
39 ans[z-left+1]=s;
40 return true;
41 }
42 p->end=false;
43 }
44 if(s==len)
45 {
46 p->count--;
47 return false;
48 }
49 if(p->count==1) count+=n-1;
50 if(p->nxt[str[s]-48]==NULL)
51 {
52 p->nxt[str[s]-48]=&buffer[c++];
53 clear(p->nxt[str[s]-48]);
54 }
55 if(solve(s+1,left,p->nxt[str[s]-48])) return true;
56 if(p->count==1) count-=n-1;
57 p->count--;
58 return false;
59 }
60 int main()
61 {
62 int test;
63 scanf("%d",&test);
64 while(test--)
65 {
66 c=1;
67 count=1;
68 head=&buffer[0];
69 clear(head);
70 scanf("%d%d%s",&z,&n,str);
71 len=strlen(str);
72 solve(0,z,head);
73 ans[0]=0;
74 for(int i=0;i<z;i++)
75 {
76 printf("%d->",i);
77 for(int j=ans[i];j<ans[i+1];j++)
78 printf("%c",str[j]);
79 printf("\n");
80 }
81 }
82 return 0;
83 }