哈夫曼树
Yes 需满足两个条件:1.HuffmanTree 结构不同,但WPL一定。子串WPL需一致
2.判断是否为前缀码
开始判断用的strstr函数,但其传值应为char *,不能用在string类型。所以后来改用substr。
substr(start,length);start为子串起始位置,length为从起始位置的长度。
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 int main() 6 { 7 string str = "123456",endStr; 8 endStr = str.substr(0,3); 9 cout<< endStr <<endl; 10 return 0; 11 } 12 //output:123
因为这里用了容器优先队列,且判断前缀码用了暴力求解,substr(start,length);函数。所以 要点:最大N&M,code长度等于63 超时了。
自己写,会快。
In 1953, David A. Huffman published his paper "A Method for the Construction of Minimum-Redundancy Codes", and hence printed his name in the history of computer science. As a professor who gives the final exam problem on Huffman codes, I am encountering a big problem: the Huffman codes are NOT unique. For example, given a string "aaaxuaxz", we can observe that the frequencies of the characters 'a', 'x', 'u' and 'z' are 4, 2, 1 and 1, respectively. We may either encode the symbols as {'a'=0, 'x'=10, 'u'=110, 'z'=111}, or in another way as {'a'=1, 'x'=01, 'u'=001, 'z'=000}, both compress the string into 14 bits. Another set of code can be given as {'a'=0, 'x'=11, 'u'=100, 'z'=101}, but {'a'=0, 'x'=01, 'u'=011, 'z'=001} is NOT correct since "aaaxuaxz" and "aazuaxax" can both be decoded from the code 00001011001001. The students are submitting all kinds of codes, and I need a computer program to help me determine which ones are correct and which ones are not.
Input Specification:
Each input file contains one test case. For each case, the first line gives an integer N (2≤N≤63), then followed by a line that contains all the NNdistinct characters and their frequencies in the following format:
c[1] f[1] c[2] f[2] ... c[N] f[N]
where c[i]
is a character chosen from {'0' - '9', 'a' - 'z', 'A' - 'Z', '_'}, andf[i]
is the frequency of c[i]
and is an integer no more than 1000. The next line gives a positive integer M (≤1000), then followed by MM student submissions. Each student submission consists of NN lines, each in the format:
c[i] code[i]
where c[i]
is the i
-th character and code[i]
is an non-empty string of no more than 63 '0's and '1's.
Output Specification:
For each test case, print in each line either "Yes" if the student's submission is correct, or "No" if not.
Note: The optimal solution is not necessarily generated by Huffman algorithm. Any prefix code with code length being optimal is considered correct.
Sample Input:
7
A 1 B 1 C 1 D 3 E 3 F 6 G 6
4
A 00000
B 00001
C 0001
D 001
E 01
F 10
G 11
A 01010
B 01011
C 0100
D 011
E 10
F 11
G 00
A 000
B 001
C 010
D 011
E 100
F 101
G 110
A 00000
B 00001
C 0001
D 001
E 00
F 10
G 11
Sample Output:
Yes
Yes
No
No
1 #include <iostream> 2 #include <cstdio> 3 #include <string> 4 #include <queue> 5 #include <algorithm> 6 using namespace std; 7 8 struct HuffTreeNode 9 { 10 char c; 11 int f; 12 }; 13 struct HuffTreeNode HuffNode[65]; 14 15 struct strNod 16 { 17 char c; 18 string code; 19 }; 20 struct strNod strNode[65]; 21 22 bool compare(strNod a, strNod b) 23 { 24 return a.code.size() < b.code.size();/*长度从小到大排序 */ 25 } 26 27 /*strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。 28 如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。*/ 29 /*[Error] cannot convert 'std::string {aka std::basic_string<char>}' to 'const char*' for argument '1' to 'char* strstr(const char*, const char*)'*/ 30 /*是子串返回true ,否则false */ 31 bool isStrstr(int N) 32 { 33 sort(strNode, strNode+N, compare); 34 for(int i = 0; i < N; i ++) { 35 for(int j = i + 1; j < N; j++) { 36 if( strNode[j].code.substr( 0, strNode[i].code.size() ) == strNode[i].code ) 37 return true; 38 } 39 } 40 return false; 41 } 42 43 int main() 44 { 45 int N; 46 scanf("%d",&N); 47 priority_queue<int, vector<int>, greater<int> > pq; 48 for(int i = 0; i < N; i++) { 49 getchar(); /*排除回车 空格的影响 */ 50 scanf("%c",&HuffNode[i].c); 51 scanf("%d",&HuffNode[i].f); 52 pq.push(HuffNode[i].f); 53 } 54 /*计算HuffmanTree WPL*/ 55 int WPL = 0; 56 int smallA,smallB; 57 while( !pq.empty() ) { 58 smallA = pq.top(); pq.pop(); /*取出两个最小的 */ 59 if( !pq.empty() ) { 60 smallB = pq.top(); pq.pop(); 61 smallA += smallB; 62 pq.push(smallA); /*求和后push进优先队列 */ 63 } 64 WPL += smallA; 65 } 66 WPL -= smallA; /*求出WPL */ 67 /* printf("WPL = %d",WPL);*/ 68 int M; 69 scanf("%d",&M); 70 for(int i = 0; i < M; i++) { 71 int checkWpl = 0; 72 for(int j = 0; j < N; j++) { 73 cin >> strNode[j].c >> strNode[j].code; 74 checkWpl += strNode[j].code.size() * HuffNode[j].f; //计算wpl 75 } 76 /* printf("checkWpl = %d",checkWpl);*/ 77 if(checkWpl == WPL) { /*WPL符合,判断是否是前缀 */ 78 if( isStrstr(N) ) /*有子串,不符合 */ 79 printf("No\n"); 80 else 81 printf("Yes\n"); 82 } 83 else 84 printf("No\n"); 85 } 86 return 0; 87 }
事实证明,自己写最小堆,并不能达到要求。大头应该是字符串比较那里。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 using namespace std; 6 7 #define MINDATA 0 /* 该值应根据具体情况定义为小于堆中所有可能元素的值 */ 8 #define ERROR -1 9 10 struct HNode { 11 int *Data; /* 存储元素的数组 */ 12 int Size; /* 堆中当前元素个数 */ 13 int Capacity; /* 堆的最大容量 */ 14 }; 15 typedef struct HNode *MinHeap; /* 堆的类型定义 */ 16 17 struct TreeNode { 18 char c; 19 int f; 20 }; 21 struct TreeNode HuffNode[65]; 22 23 struct strNod 24 { 25 char c; 26 string code; 27 }; 28 struct strNod strNode[65]; 29 MinHeap CreateHeap( int MaxSize ); 30 bool IsFull( MinHeap H ); 31 bool Insert( MinHeap H, int X ); 32 bool IsEmpty( MinHeap H ); 33 int DeleteMin( MinHeap H ); 34 35 bool compare(strNod a, strNod b) 36 { 37 return a.code.size() < b.code.size();/*长度从小到大排序 */ 38 } 39 40 /*strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。 41 如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。*/ 42 /*[Error] cannot convert 'std::string {aka std::basic_string<char>}' to 'const char*' for argument '1' to 'char* strstr(const char*, const char*)'*/ 43 /*是子串返回true ,否则false */ 44 bool isStrstr(int N) 45 { 46 sort(strNode, strNode+N, compare); 47 for(int i = 0; i < N; i ++) { 48 for(int j = i + 1; j < N; j++) { 49 if( strNode[j].code.substr( 0, strNode[i].code.size() ) == strNode[i].code ) 50 return true; 51 } 52 } 53 return false; 54 } 55 56 int main() 57 { 58 int N; 59 scanf("%d",&N); 60 MinHeap Heap = CreateHeap(N); 61 for(int i = 0; i < N; i++) { 62 getchar(); /*排除回车 空格的影响 */ 63 scanf("%c",&HuffNode[i].c); 64 scanf("%d",&HuffNode[i].f); 65 Insert(Heap, HuffNode[i].f); 66 } 67 68 //计算WPL的值 69 int WPL = 0; 70 int smallA, smallB; 71 while( !IsEmpty(Heap) ) { 72 smallA = DeleteMin(Heap); 73 if( !IsEmpty(Heap) ) { 74 smallB = DeleteMin(Heap); 75 smallA += smallB; 76 Insert( Heap, smallA); 77 } 78 WPL += smallA; 79 } 80 WPL -= smallA; 81 // printf("WPL = %d\n",WPL); 82 83 int M; 84 scanf("%d",&M); 85 for(int i = 0; i < M; i++) { 86 int checkWpl = 0; 87 for(int j = 0; j < N; j++) { 88 cin >> strNode[j].c >> strNode[j].code; 89 checkWpl += strNode[j].code.size() * HuffNode[j].f; //计算wpl 90 } 91 /* printf("checkWpl = %d",checkWpl);*/ 92 if(checkWpl == WPL) { /*WPL符合,判断是否是前缀 */ 93 if( isStrstr(N) ) /*有子串,不符合 */ 94 printf("No\n"); 95 else 96 printf("Yes\n"); 97 } 98 else 99 printf("No\n"); 100 } 101 return 0; 102 } 103 104 /* 创建容量为MaxSize的空的最小堆 */ 105 MinHeap CreateHeap( int MaxSize ) 106 { 107 108 MinHeap H = (MinHeap)malloc(sizeof(struct HNode)); 109 H->Data = (int*)malloc((MaxSize+1)*sizeof(int)); 110 H->Size = 0; 111 H->Capacity = MaxSize; 112 H->Data[0] = MINDATA; /* 定义"哨兵"为小于堆中所有可能元素的值*/ 113 return H; 114 } 115 116 bool IsFull( MinHeap H ) 117 { 118 return (H->Size == H->Capacity); 119 } 120 121 /* 将元素X插入最小堆H,其中H->Data[0]已经定义为哨兵 */ 122 bool Insert( MinHeap H, int X ) 123 { 124 if ( IsFull(H) ) { 125 printf("最小堆已满"); 126 return false; 127 } 128 int i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */ 129 for ( ; H->Data[i/2] > X; i /= 2 ) 130 H->Data[i] = H->Data[i/2]; /* 上滤X */ 131 H->Data[i] = X; /* 将X插入 */ 132 return true; 133 } 134 135 bool IsEmpty( MinHeap H ) 136 { 137 return (H->Size == 0); 138 } 139 140 /* 从最小堆H中取出键值为最小的元素,并删除一个结点 */ 141 int DeleteMin( MinHeap H ) 142 { 143 int Parent, Child; 144 int MinItem, X; 145 146 if ( IsEmpty(H) ) { 147 printf("最小堆已为空"); 148 return ERROR; 149 } 150 151 MinItem = H->Data[1]; /* 取出根结点存放的最小值 */ 152 /* 用最小堆中最后一个元素从根结点开始向上过滤下层结点 */ 153 X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */ 154 for( Parent = 1; Parent * 2 <= H->Size; Parent = Child ) { 155 Child = Parent * 2; 156 if( (Child != H->Size) && (H->Data[Child] > H->Data[Child+1]) ) 157 Child++; /* Child指向左右子结点的较小者 */ 158 if( X <= H->Data[Child] ) break; /* 找到了合适位置 */ 159 else /* 下滤X */ 160 H->Data[Parent] = H->Data[Child]; 161 } 162 H->Data[Parent] = X; 163 164 return MinItem; 165 }
剪枝、。。。失败
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 using namespace std; 6 7 #define MINDATA 0 /* 该值应根据具体情况定义为小于堆中所有可能元素的值 */ 8 #define ERROR -1 9 10 struct HNode { 11 int *Data; /* 存储元素的数组 */ 12 int Size; /* 堆中当前元素个数 */ 13 int Capacity; /* 堆的最大容量 */ 14 }; 15 typedef struct HNode *MinHeap; /* 堆的类型定义 */ 16 17 struct TreeNode { 18 char c; 19 int f; 20 }; 21 struct TreeNode HuffNode[65]; 22 23 struct strNod 24 { 25 char c; 26 string code; 27 }; 28 struct strNod strNode[65]; 29 MinHeap CreateHeap( int MaxSize ); 30 bool IsFull( MinHeap H ); 31 bool Insert( MinHeap H, int X ); 32 bool IsEmpty( MinHeap H ); 33 int DeleteMin( MinHeap H ); 34 35 bool compare(strNod a, strNod b) 36 { 37 return a.code.size() < b.code.size();/*长度从小到大排序 */ 38 } 39 40 /*strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。 41 如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。*/ 42 /*[Error] cannot convert 'std::string {aka std::basic_string<char>}' to 'const char*' for argument '1' to 'char* strstr(const char*, const char*)'*/ 43 /*是子串返回true ,否则false */ 44 bool isStrstr(int N) 45 { 46 sort(strNode, strNode+N, compare); 47 for(int i = 0; i < N; i ++) { 48 for(int j = i + 1; j < N; j++) { 49 if( strNode[j].code.substr( 0, strNode[i].code.size() ) == strNode[i].code ) 50 return true; 51 } 52 } 53 return false; 54 } 55 56 int main() 57 { 58 int N; 59 scanf("%d",&N); 60 MinHeap Heap = CreateHeap(N); 61 for(int i = 0; i < N; i++) { 62 getchar(); /*排除回车 空格的影响 */ 63 scanf("%c",&HuffNode[i].c); 64 scanf("%d",&HuffNode[i].f); 65 Insert(Heap, HuffNode[i].f); 66 } 67 68 //计算WPL的值 69 int WPL = 0; 70 int smallA, smallB; 71 while( !IsEmpty(Heap) ) { 72 smallA = DeleteMin(Heap); 73 if( !IsEmpty(Heap) ) { 74 smallB = DeleteMin(Heap); 75 smallA += smallB; 76 Insert( Heap, smallA); 77 } 78 WPL += smallA; 79 } 80 WPL -= smallA; 81 // printf("WPL = %d\n",WPL); 82 83 int M; 84 85 scanf("%d",&M); 86 for(int i = 0; i < M; i++) { 87 int checkWpl = 0; 88 bool overFlag = false; //其中一个字符串超出长度 89 for(int j = 0; j < N; j++) { 90 cin >> strNode[j].c >> strNode[j].code; 91 if(strNode[j].code.size() > N-1) { //如果有size超出N-1 一定不满足WPL 这里卡一刀希望快些 92 overFlag = true; 93 break; 94 } 95 checkWpl += strNode[j].code.size() * HuffNode[j].f; //计算wpl 96 } 97 /* printf("checkWpl = %d",checkWpl);*/ 98 if(checkWpl == WPL && !overFlag) { /*WPL符合,判断是否是前缀 */ 99 if( isStrstr(N) ) /*有子串,不符合 */ 100 printf("No\n"); 101 else 102 printf("Yes\n"); 103 } 104 else 105 printf("No\n"); 106 } 107 return 0; 108 } 109 110 /* 创建容量为MaxSize的空的最小堆 */ 111 MinHeap CreateHeap( int MaxSize ) 112 { 113 114 MinHeap H = (MinHeap)malloc(sizeof(struct HNode)); 115 H->Data = (int*)malloc((MaxSize+1)*sizeof(int)); 116 H->Size = 0; 117 H->Capacity = MaxSize; 118 H->Data[0] = MINDATA; /* 定义"哨兵"为小于堆中所有可能元素的值*/ 119 return H; 120 } 121 122 bool IsFull( MinHeap H ) 123 { 124 return (H->Size == H->Capacity); 125 } 126 127 /* 将元素X插入最小堆H,其中H->Data[0]已经定义为哨兵 */ 128 bool Insert( MinHeap H, int X ) 129 { 130 if ( IsFull(H) ) { 131 printf("最小堆已满"); 132 return false; 133 } 134 int i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */ 135 for ( ; H->Data[i/2] > X; i /= 2 ) 136 H->Data[i] = H->Data[i/2]; /* 上滤X */ 137 H->Data[i] = X; /* 将X插入 */ 138 return true; 139 } 140 141 bool IsEmpty( MinHeap H ) 142 { 143 return (H->Size == 0); 144 } 145 146 /* 从最小堆H中取出键值为最小的元素,并删除一个结点 */ 147 int DeleteMin( MinHeap H ) 148 { 149 int Parent, Child; 150 int MinItem, X; 151 152 if ( IsEmpty(H) ) { 153 printf("最小堆已为空"); 154 return ERROR; 155 } 156 157 MinItem = H->Data[1]; /* 取出根结点存放的最小值 */ 158 /* 用最小堆中最后一个元素从根结点开始向上过滤下层结点 */ 159 X = H->Data[H->Size--]; /* 注意当前堆的规模要减小 */ 160 for( Parent = 1; Parent * 2 <= H->Size; Parent = Child ) { 161 Child = Parent * 2; 162 if( (Child != H->Size) && (H->Data[Child] > H->Data[Child+1]) ) 163 Child++; /* Child指向左右子结点的较小者 */ 164 if( X <= H->Data[Child] ) break; /* 找到了合适位置 */ 165 else /* 下滤X */ 166 H->Data[Parent] = H->Data[Child]; 167 } 168 H->Data[Parent] = X; 169 170 return MinItem; 171 }