题意:模拟手机九宫格输入法,输入w个字符串并给出每个字符串出现的次数,然后输入p组查询,每组的查询由一串数字组成,每输入一个数字输出到当前为止最有可能的字符串(如果不存在就输出MANUALLY),出现次数越多的字符串可能性越大。
题解:看题意肯定是要在字典树上操作的,但是与一般字典树不同的是这里多了一项出现次数。并且查询的时候一个数字可能同时代表几个字母,要找出其中出现次数最多的一个。所以首先在字典树建树时我们就要把每个单词中的每次字母出现次数都加上当前这个单词出现的次数。然后用dfs进行查找,我们遍历这个数字所代表的手机键包含的所有字符,如果在字典树中出现过就继续递归往下找,直到找到题目所要求的的长度,找到其中出现次数最大的一个字符,并输出根节点到这个字符的所有字符。
附上代码:
#include
#include
#include
#include
using namespace std;
const int maxn=110;
char phone[][4] = {{'a','b','c'},{'d','e','f'},{'g','h','i'},{'j','k','l'},{'m','n','o'},{'p','q','r','s'},{'t','u','v'},{'w','x','y','z'}};
//phone表示手机上九个键每个键表示的字母
int num[8] = {3,3,3,3,3,4,3,4};//num表示每个数字上面包含几个字母
int w;//w保存每个字符在字典树每层出现的频率
char ans[maxn],s[maxn],str[maxn],a[maxn];//ans数组记录最终答案
struct node
{
int cnt;///cnt记录每个字母出现的频率
struct node *next[26];
node()
{
cnt = 0;
memset(next,0,sizeof(next));
}
};
node *root=NULL;
void buildtire(char *ss,int k)
{
node*q=root;
node *temp=NULL;
for(int i=0;inext[v] == NULL)
{
temp = new node;
q->next[v] = temp;
q = q->next[v];
(q->cnt)+=k;///在出入时记录好每个字符出现的频率
}
else{
q = q->next[v];
(q->cnt)+=k;
}
}
}
void dfs(int st,int len,node *tr)
///dfs查找的思路是遍历这个数字包含的所有字符,如果在字典树中出现就继续递归往下找,
///直到找到题目所要求的长度,找到其中出现次数最大一个字符,并输出从根节点到这个字符所表示的字符串
{
if(st == len)///找到题目所要求长度
{
if(tr->cnt>w)///最后的答案是出现次数最大的
{
w = tr->cnt;
for(int i=0;inext[c-'a']!=NULL)
{ ///因为找到出现次数最大的字符时,它前边的字符必须可能在以前输入数字时有出现的可能,
///所以这里要控制某个数字包含的字母只有在字典树中的字符才往下递归
s[st] = c;
dfs(st+1,len,tr->next[c-'a']);
}
}
}
int main()
{
int T;
scanf("%d",&T);
int c=0;
while(T--)
{
root = new node;
int n,k;
scanf("%d",&n);
memset(a,0,sizeof(a));
for(int i=0;i0)
printf("%s\n",ans);
else
printf("MANUALLY\n");
}
printf("\n");
}
printf("\n");
}
return 0;
}
这题虽然常规方法可以用字典树+dfs做,但是看到还有人用map来做,果然有了STL就有了全世界。首先对于每个字母都有自己对应的数字,所以对于每个数字序列都有它对应的字符串,那就可以用一个map来离线保存每个数字序列最有可能出现的字符串。而对于每个数字序列最有可能对应的字符串,可以在一开始输入单词时就对每个单词进行映射把它变成数字序列,虽然数字对应单词不是唯一的,但是单词对应数字是唯一的,然后在不断插入单词的过程中,对应每一个前缀都更新一下这个前缀对应的数字序列,最后查询的时候直接查询输出。(给出这个做法的原博客链接:点击打开链接)
#include
#include
#include
#include
#include