2.9
https://pintia.cn/problem-sets/16/problems/671
哈夫曼树
字典树做法:
#include <cstdio> #include <cstring> #include <queue> using namespace std; int n,rc,c,d,num[200],k,flag; char s[2],t[100]; int trie[10000][2],ind,en[10000]; void build(char *str) {//字典树,前缀树 int r = 0,i = 0; while(str[i]) { int e = str[i ++] - '0'; if(!trie[r][e]) {//A 00000 trie[r][e] = ++ ind;//B 00001 // ind是当前第几个字符 } //C 0001 r = trie[r][e];// D 001 if(en[r] == 1) flag = 1;// E 01 if(str[i]) en[r] = 2; //F 10 } //G 11 if(en[r]) flag = 1; en[r] = 1; } int main() { scanf("%d",&n); priority_queue<int,vector<int>,greater<int> > q;//升序队列:最小堆 for(int i = 0;i < n;i ++) { scanf("%s %d",s,&d); num[(int)s[0]] = d;//d是出现频率 q.push(d); } while(q.size() > 1) {//利用优先队列计算 权值: d = q.top(); q.pop(); d += q.top(); q.pop(); q.push(d);//计算原理和 哈夫曼树的计算权值一样. rc += d; }//rc是最小权值 scanf("%d",&k);//k组判断 for(int i = 0;i < k;i ++) { c = ind = flag = 0;//初始化 memset(trie,0,sizeof(trie)); memset(en,0,sizeof(en)); for(int j = 0;j < n;j ++) { scanf("%s %s",s,t); int len = strlen(t); if(len >= n) {flag = 1;break;}//如果长度超出了,就错误了 build(t); c += num[int(s[0])] * len;//s[0]是当前该字母,s[1]是读入的空格; //num中存的是出现的次数 } printf("%s\n",c == rc && !flag ? "Yes" : "No"); } }
用sort解法:(数据强度弱的时候可以ac)
#include<bits/stdc++.h> using namespace std; int n,k,val; string str[10010]; map<char,int>m; bool check() { sort(str,str+n); for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) if(str[j].substr(0,str[i].size())==str[i]) return false; return true; } int main() { cin>>n; priority_queue<int,vector<int>,greater<int>>q; for(int i=0;i<n;i++) { char c;int x; cin>>c>>x; m[c]=x; q.push(x); } while(1) { int tp=q.top();q.pop(); if(q.empty()) break; tp+=q.top();q.pop(); q.push(tp); val+=tp; } cin>>k; while(k--) { int len=0,flag=0; for(int i=0;i<n;i++) { char c; cin>>c>>str[i]; len+=m[c]*str[i].size(); } if(len==val&&check()) puts("Yes"); else puts("No"); } }