HDU1857题解(逆向思维trie)
题目link:http://acm.hdu.edu.cn/showproblem.php?pid=1857
先简述一下题目:
有一个RXC的字母矩形,R,C在500内,要匹配m个单词,m在100000内,每个单词长度不超过20,匹配方法为向右或者向下,或者右下,即三个方向,0度,90度,45度。
现在要输出:如果匹配成功,输出第一个字母的坐标,如果有多个匹配,输出最左上的,如果不成功,输出-1 -1。
如果你使用简单的匹配,或者搜索,超时无限次,如果你字母矩阵构树单词构trie树,必超内存,自己可以想想。
所以我也很无奈,这是我比赛时候遇到的一题,当时我开了这题,很无力……
这题目标志着我开始学习trie树,经过两天的思考,和参阅别人的思想,我们用逆向思维来做,以需匹配的单词构树(只有100000个),用字母矩阵来匹配,所以在插入的时候,我们给要匹配的单词编号,用RR,CC数组来记录对应单词的坐标,初始化为0(我用的是0,也可以memset( ,-1, )),之后查找的时候,就传入(行数+1,列数+1,)之所以加1,是因为想用0来表示没成功匹配。我在trie里写了terminable,id(属于第几个单词插入)属性,在查找过程,只要遇到结点terminable,就比较是否记载过,没记载过,就将RR[id],CC[id]标记为传入参数r,c。最后顺序输出即可。
想清楚后,昨晚很自信地开始拍了,经过各种调试,总算过了sample了……马上就提交了,这次终于没有TLE了,且速度十分快……在c++提交是wa,在g++提交是RE。
这时候已经很夜了,我心想,先休息吧……
每次带着问题休息,效果都会很差,想了很久,还是觉得没问题,最后在郁闷与猜疑中睡去了.
今天醒来,发现了一个很基本的错误,我的数组开得太小了……改了一下,马上就过掉了……!!!!
- #include<iostream>
- #include<cstdio>
- #include<string>
- #include<cstring>
- #include<cmath>
- #include<cstdlib>
- using namespace std;
- template<int Size>
- struct trie_node{
- bool terminable; //表示节点为字符串的结尾
- int node; //子节点的个数
- int id;
- trie_node *child[Size]; //儿子节点
- trie_node():terminable(false), node(){
- memset(child,,sizeof(child)); //初始化节点
- }
- };
- int RR[],CC[];
- template<int Size,typename Index>
- class trie{
- public:
- //定义类名
- typedef trie_node<Size> node_type;
- typedef trie_node<Size> *link_type;
- //构造函数
- trie(Index i=Index()):index(i){ }
- //清空函数,用于析构
- void clear(){
- clear_node(root);
- for(int i=;i<Size;i++)
- root.child[i]=;
- }
- //插入
- template<typename Iterator>
- void insert(Iterator begin,Iterator end,int i){
- link_type cur= &root;//当前插入结点为根
- while(begin!=end){
- if(cur->child[index[*begin]]){//插入过
- cur=cur->child[index[*begin]];
- ++(cur->node);
- }else{
- cur->child[index[*begin]]=new node_type;
- ++(cur->child[index[*begin]]->node);
- cur=cur->child[index[*begin]];
- }
- begin++; //迭代器往前走!
- }
- cur->terminable=true;
- cur->id=i;
- }
- //重载c风格插入
- void insert(const char * str,int i){
- insert(str,str+strlen(str), i);
- }
- //查找
- template <typename Iterator>
- void find(Iterator begin,Iterator end,int r,int c){
- link_type cur=&root;
- while(begin!=end){
- if(cur->terminable){
- if(RR[cur->id]==){
- RR[cur->id]=r;
- CC[cur->id]=c;
- }
- }
- if(!cur->child[index[*begin]]) //没有节点啊!!!
- return ;
- cur=cur->child[index[*begin]];
- begin++;
- }
- if( cur->terminable) {//是否为字符串
- if(RR[cur->id]==){
- RR[cur->id]=r;
- CC[cur->id]=c;
- }
- }
- }
- //重载c风格
- void find(const char *str,int r,int c){
- find(str,str+strlen(str),r,c);
- }
- private:
- //清空
- void clear_node(node_type cur){
- for(int i=;i<Size;i++){
- if(cur.child[i]==)continue; //不存在
- clear_node(*cur.child[i]);
- delete cur.childe[i];
- cur.child[i]=;
- if(--cur.node==) break; //没有节点了
- }
- }
- //根
- node_type root;
- //字符转索引,类似hash
- Index index;
- };
- class IndexClass{
- public:
- int operator[](const char key){
- return key%; //一个映射
- }
- };
- char cc[][];
- char s[];
- int mini(int a,int b){
- return a>b?b:a;
- }
- int main(){
- trie<,IndexClass> t;
- int R,C,i,j,l,ed;
- scanf("%d%d",&R,&C);
- getchar(); //读掉回车
- for( i=;i<R;i++)
- {
- gets(cc[i]);
- }
- int N=;
- while(gets(s)&&s[]!='-'){
- if(s[]){
- t.insert(s,N); //用每一个要查找的单词构树
- N++;
- }
- }
- for(i=;i<R;i++)
- for( j=;j<C;j++){
- //向下
- memset(s,,sizeof(s));
- if(i+<R) ed=;
- else ed=R-i;
- for(l=;l<ed;l++){
- s[l]=cc[i+l][j];
- }
- t.find(s,i+,j+);
- //向右
- memset(s,,sizeof(s));
- if(j+<C) ed=;
- else ed=C-j;
- for( l=;l<ed;l++){
- s[l]=cc[i][j+l];
- }
- t.find(s,i+,j+);
- //右下
- memset(s,,sizeof(s));
- if(i+<R&&j+<C) ed=;
- else ed=mini(C-j,R-i);
- for( l=;l<ed;l++){
- s[l]=cc[i+l][j+l];
- }
- t.find(s,i+,j+);
- }
- for( i=;i<N;i++){
- if(RR[i]!=||CC[i]!=)
- printf("%d %d\n",RR[i]-,CC[i]-);
- else puts("-1 -1");
- }
- return ;
- }
HDU1857题解(逆向思维trie)的更多相关文章
- tyvj1161聚会的名单(trie树)
背景 Background 明天就是candy的生日,candy又会邀请自己的一大堆好友来聚会了!哎!又要累坏飘飘乎居士了!! 描述 Description 明天就是candy的生日.晚上,c ...
- HDU1671 - Phone List(Trie树)
题目大意 给定一些电话号码,判断是否有电话号码是其他电话号码的前缀 题解 裸Trie树嘛~~~~只需要一个插入过程即可,假设X是Y的前缀,在插入的过程中有两种情况,X在Y之前插入,那么在插入Y的时候经 ...
- hiho #1014 : Trie树(模板)
Trie树 [题目链接]Trie树 &题意: 输入 输入的第一行为一个正整数n,表示词典的大小,其后n行,每一行一个单词(不保证是英文单词,也有可能是火星文单词哦),单词由不超过10个的小写英 ...
- HDU 1251 统计难题(Trie)
统计难题 [题目链接]统计难题 [题目类型]Trie &题解: Trie的模板题,只不过这题坑点在没给数据范围,改成5e5就可以过了,用的刘汝佳蓝书模板 &代码: #include & ...
- Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset Trie
题目链接: http://codeforces.com/contest/706/problem/D D. Vasiliy's Multiset time limit per test:4 second ...
- 算法复习——trie树(poj2001)
题目: 题目描述 给出 n 个单词(1<=n<=1000),求出每个单词的非公共前缀,如果没有,则输出自己. 输入格式 输入 N 个单词,每行一个,每个单词都是由 1-20 个小写字母构成 ...
- hihoCoder #1014 : Trie树 [ Trie ]
传送门 #1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互 ...
- CF456D A Lot of Games (字典树+DP)
D - A Lot of Games CF#260 Div2 D题 CF#260 Div1 B题 Codeforces Round #260 CF455B D. A Lot of Games time ...
- Wild Words
poj1816:http://poj.org/problem?id=1816 题意:给你n个模板串,然后每个串除了字母,还有?或者*,?可以代替任何非空单个字符,*可以替代任何长度任何串,包括空字符串 ...
随机推荐
- ShareSDK for iOS 2.9.0已经公布
ShareSDK for iOS v2.9.0已经公布,本次更新内容包含: 1.修复Facebook获取用户信息报错问题 2.修复Instagram在iPad上显示分享菜单错误问题,须要指定菜单容器. ...
- xtrabackup原理0
- python中文处理之encode/decode函数
python中文处理相信迷惑过不少同学.下面说说python2/3的encode和decode函数. python2中,使用decode()和encode()来进行解码和编码,以unicode类型作为 ...
- 03 InnoDB锁问题
InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我们先介绍一点背景知识 ...
- 使用ReactiveCocoa开发RSS阅读器
目前已经完成的功能有对RSS的解析和Atom解析,RSS内容本地数据库存储和读取,抓取中状态进度展示,标记阅读状态,标记全部已读等.这些功能里我对一些异步操作产生的数据采用了ReactiveCocoa ...
- [课程相关]homework-03
零.准备工作 这次的作业是结对编程,因为一些原因我们的队伍一共有三个人,成员为:梁杰.夏天晗.谢祖三.由于大家不在一个班,交流起来也不是特别方便,所以我们经过讨论决定三个人约一个时间在一起完成这次作业 ...
- Linux串口编程(转载)
在嵌入式Linux中,串口是一个字设备,访问具体的串行端口的编程与读/写文件 的操作类似,只需打开相应的设备文件即可操作.串口编程特殊在于串 口通信时相关参数与属性的设置.嵌入式Linux的串口编程时 ...
- AI 对不起 我还爱着你
艾弗森,对不起,我还爱着你.有时候我自己都不知道自己我怎么了,直到最后才发现,我还爱着你. 那天起,我认识了你,便一发不可收拾.这些天,谢谢你,似乎因为你的影响让我改变了,坚持了许多.致以至今我才发现 ...
- Servlet & JSP - Listener
Servlet API 中的 6 个事件类 1. ServletContextEvent:该类表示上下文事件,当应用上下文对象发生改变,例如创建或销毁上下文对象时,将触发上下文事件. 2. Servl ...
- EF中"实体类型 XXXXX 不是当前上下文的模型的一部分。" 原因
用T4模版生成的数据库映射文件.cs对应不上数据库的字段而引起的错误(我是修改了cs里面的属性),只要根据数据库字段,修改回来就OK.问题就解决了.