POJ1451 - 字典树的变型

在给学校新队员上编程课时,作者经历了一次紧张的高精度加法演示,差点怯场。通过狐狸大大及时的帮助,最终解决了问题,并将这一过程与实际手机输入法应用相结合,提出了一道具有实用性的编程题。通过字典树的动态构造和维护,实现了根据按键输入获取推荐字串的功能。尽管过程中遇到了bug,但最终成功解决,展示了编程中的挑战与成就感。

上个周末给学校新队员上课...很是紧张..周日那场想来现场coding..就是很简单的高精度加法...结果怯场了..还是狐狸大大上来救了我..好丢人~~囧..这一向状态一直怪怪的~~这道题起码卡了三天吧~~其实这三天也是招新各种事~~没多大心思来做题~~昨天晚上终于把这题搞定了~~

题意就是说给一个字典...并同时给出每个单词的出现次数...是想一下手机的输入法...然后按手机的输入一串按键~~每按一下按键输出一个推荐字串~~这个字串是在字典中次数最多的前缀..如果有两个相等的..输出字典序靠前的....如果输入一串按键,在字典里一个也没得.那就只能输出"MANUALLY"...其实感觉这题是很实用很现实的~~咱们平时用手机输入法就是有这个性质~~

这道题还是的字典树...要求的是前缀出现次数最多..每个点的定义:

struct node { int s[26],x,father,w; char c; }

这道题因为有多组数据..动态分配空间如果不释放又很浪费..释放又很耗时...所以采取了开辟静态空间再来链接的伪指针方式....s[ ] 则是记录起孩子是否能链接到哪个位置...x是记录有多少个单词会经过这个点...所以在构造字典树时..每经过一个点..这个点的x就++...father是记录字典树中每个点的父亲..这里是为了这道题后面的输出方便..w是记录当前点所在层数..同样也是为了后面的处理方便...c是当前点是哪个字符..同样也是为了后面的处理方便....s[ ],father,x,w,c在构造树时都能得到准确的值....

构造树的过程和我上一个日志类似..只是多加几个运算得到father,x,w,c而已了~~就直接看构造完树后怎么得到想要的结果..做的话用一个队列来维护..先是超级头结点0入内..可以想象一下...每一次读一个字符就往下做一层...而队列的目的就是看每一层还有多少点可以进行拓展.....每次读一个字符c..如果不是'1'就继续做...扫描所有还能符合条件的上一层的点..找到他们孩子中即在手机按键上是这个c-'0'又其存在...这种点先入队..然后判断其x值..找到所有孩子中满足条件的点..如果没有一个点能入队代表不存在符合输入信息的前缀了~~就要跳出输出"MANUALLY"...如果能找到最佳前缀...则输出..输出的话就从这个最佳的点开始用father往上走..直到走到father为0..就能得到这个前缀了..

自己在写的时候调了很多bug...整了不少时间才搞定...还是自己队字典树不大熟练吧...囧...


Program:

#include<iostream> #include<queue> #define MAXN 1002 using namespace std; struct node { int s[26],x,father,w; char c; }a[10001]; int t,T,w,m,i,p[MAXN],l,g,newdata; int turn[26]={2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9,9}; char s[MAXN][101],c; void find(int h,int k) { if (k>l) return; a[h].x+=p[i]; if (!a[h].s[s[i][k]-'a']) { g++; a[h].s[s[i][k]-'a']=g; a[g].father=h; a[g].w=k+1; a[g].c=s[i][k]; if (k==l) a[g].x=p[i]; else a[g].x=0; } find(a[h].s[s[i][k]-'a'],k+1); } queue<int> myqueue; void make() { int h,k,m,i,step=0; char s[111]; while (!myqueue.empty()) myqueue.pop(); myqueue.push(0); while (scanf("%c",&c)!=EOF) { if (c=='1') return; h=myqueue.front(); m=0; while (a[h].w==step) { for (i=0;i<26;i++) if ((turn[i]==c-'0')&&(a[h].s[i])) { myqueue.push(a[h].s[i]); if (a[a[h].s[i]].x>m) { k=a[h].s[i]; m=a[k].x; } } myqueue.pop(); if (myqueue.empty()) break; h=myqueue.front(); } if (!m) goto A; step++; s[step]='\0'; for (i=step-1;i>=0;i--) { s[i]=a[k].c; k=a[k].father; } puts(s); } A: printf("MANUALLY\n"); while (scanf("%c",&c)!=EOF) { if (c=='1') return; printf("MANUALLY\n"); } return; } int main() { scanf("%d",&T); for (t=1;t<=T;t++) { scanf("%d",&w); g=0; memset(a,0,sizeof(a)); p[0]=0; for (i=1;i<=w;i++) { scanf("%s%d",s[i],&p[i]); l=strlen(s[i])-1; find(0,0); } printf("Scenario #%d:\n",t); scanf("%d",&m); a[0].x=0; while (m--) { getchar(); make(); printf("\n"); } printf("\n"); } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值