题目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。

这时候已经很夜了,我心想,先休息吧……

每次带着问题休息,效果都会很差,想了很久,还是觉得没问题,最后在郁闷与猜疑中睡去了.

今天醒来,发现了一个很基本的错误,我的数组开得太小了……改了一下,马上就过掉了……!!!!

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<string>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<cstdlib>
  7. using namespace std;
  8. template<int Size>
  9. struct trie_node{
  10.  
  11. bool terminable; //表示节点为字符串的结尾
  12. int node; //子节点的个数
  13. int id;
  14. trie_node *child[Size]; //儿子节点
  15. trie_node():terminable(false), node(){
  16. memset(child,,sizeof(child)); //初始化节点
  17. }
  18.  
  19. };
  20. int RR[],CC[];
  21. template<int Size,typename Index>
  22. class trie{
  23. public:
  24. //定义类名
  25. typedef trie_node<Size> node_type;
  26. typedef trie_node<Size> *link_type;
  27.  
  28. //构造函数
  29. trie(Index i=Index()):index(i){ }
  30.  
  31. //清空函数,用于析构
  32. void clear(){
  33. clear_node(root);
  34. for(int i=;i<Size;i++)
  35. root.child[i]=;
  36. }
  37. //插入
  38. template<typename Iterator>
  39. void insert(Iterator begin,Iterator end,int i){
  40.  
  41. link_type cur= &root;//当前插入结点为根
  42. while(begin!=end){
  43. if(cur->child[index[*begin]]){//插入过
  44. cur=cur->child[index[*begin]];
  45. ++(cur->node);
  46.  
  47. }else{
  48. cur->child[index[*begin]]=new node_type;
  49. ++(cur->child[index[*begin]]->node);
  50. cur=cur->child[index[*begin]];
  51.  
  52. }
  53.  
  54. begin++; //迭代器往前走!
  55. }
  56. cur->terminable=true;
  57. cur->id=i;
  58.  
  59. }
  60.  
  61. //重载c风格插入
  62. void insert(const char * str,int i){
  63. insert(str,str+strlen(str), i);
  64. }
  65.  
  66. //查找
  67. template <typename Iterator>
  68. void find(Iterator begin,Iterator end,int r,int c){
  69. link_type cur=&root;
  70. while(begin!=end){
  71.  
  72. if(cur->terminable){
  73.  
  74. if(RR[cur->id]==){
  75.  
  76. RR[cur->id]=r;
  77. CC[cur->id]=c;
  78. }
  79. }
  80.  
  81. if(!cur->child[index[*begin]]) //没有节点啊!!!
  82. return ;
  83.  
  84. cur=cur->child[index[*begin]];
  85.  
  86. begin++;
  87.  
  88. }
  89. if( cur->terminable) {//是否为字符串
  90.  
  91. if(RR[cur->id]==){
  92.  
  93. RR[cur->id]=r;
  94. CC[cur->id]=c;
  95. }
  96. }
  97.  
  98. }
  99.  
  100. //重载c风格
  101. void find(const char *str,int r,int c){
  102.  
  103. find(str,str+strlen(str),r,c);
  104. }
  105.  
  106. private:
  107.  
  108. //清空
  109. void clear_node(node_type cur){
  110. for(int i=;i<Size;i++){
  111. if(cur.child[i]==)continue; //不存在
  112. clear_node(*cur.child[i]);
  113. delete cur.childe[i];
  114. cur.child[i]=;
  115. if(--cur.node==) break; //没有节点了
  116.  
  117. }
  118.  
  119. }
  120.  
  121. //根
  122. node_type root;
  123. //字符转索引,类似hash
  124. Index index;
  125.  
  126. };
  127.  
  128. class IndexClass{
  129. public:
  130. int operator[](const char key){
  131. return key%; //一个映射
  132.  
  133. }
  134.  
  135. };
  136. char cc[][];
  137. char s[];
  138. int mini(int a,int b){
  139. return a>b?b:a;
  140. }
  141. int main(){
  142. trie<,IndexClass> t;
  143. int R,C,i,j,l,ed;
  144. scanf("%d%d",&R,&C);
  145. getchar(); //读掉回车
  146. for( i=;i<R;i++)
  147. {
  148.  
  149. gets(cc[i]);
  150. }
  151.  
  152. int N=;
  153. while(gets(s)&&s[]!='-'){
  154. if(s[]){
  155. t.insert(s,N); //用每一个要查找的单词构树
  156. N++;
  157. }
  158.  
  159. }
  160.  
  161. for(i=;i<R;i++)
  162. for( j=;j<C;j++){
  163. //向下
  164. memset(s,,sizeof(s));
  165. if(i+<R) ed=;
  166. else ed=R-i;
  167. for(l=;l<ed;l++){
  168. s[l]=cc[i+l][j];
  169.  
  170. }
  171.  
  172. t.find(s,i+,j+);
  173. //向右
  174. memset(s,,sizeof(s));
  175. if(j+<C) ed=;
  176. else ed=C-j;
  177. for( l=;l<ed;l++){
  178. s[l]=cc[i][j+l];
  179.  
  180. }
  181.  
  182. t.find(s,i+,j+);
  183.  
  184. //右下
  185. memset(s,,sizeof(s));
  186. if(i+<R&&j+<C) ed=;
  187. else ed=mini(C-j,R-i);
  188. for( l=;l<ed;l++){
  189. s[l]=cc[i+l][j+l];
  190.  
  191. }
  192.  
  193. t.find(s,i+,j+);
  194.  
  195. }
  196.  
  197. for( i=;i<N;i++){
  198.  
  199. if(RR[i]!=||CC[i]!=)
  200. printf("%d %d\n",RR[i]-,CC[i]-);
  201. else puts("-1 -1");
  202. }
  203.  
  204. return ;
  205.  
  206. }

HDU1857题解(逆向思维trie)的更多相关文章

  1. tyvj1161聚会的名单(trie树)

    背景 Background 明天就是candy的生日,candy又会邀请自己的一大堆好友来聚会了!哎!又要累坏飘飘乎居士了!! 描述 Description     明天就是candy的生日.晚上,c ...

  2. HDU1671 - Phone List(Trie树)

    题目大意 给定一些电话号码,判断是否有电话号码是其他电话号码的前缀 题解 裸Trie树嘛~~~~只需要一个插入过程即可,假设X是Y的前缀,在插入的过程中有两种情况,X在Y之前插入,那么在插入Y的时候经 ...

  3. hiho #1014 : Trie树(模板)

    Trie树 [题目链接]Trie树 &题意: 输入 输入的第一行为一个正整数n,表示词典的大小,其后n行,每一行一个单词(不保证是英文单词,也有可能是火星文单词哦),单词由不超过10个的小写英 ...

  4. HDU 1251 统计难题(Trie)

    统计难题 [题目链接]统计难题 [题目类型]Trie &题解: Trie的模板题,只不过这题坑点在没给数据范围,改成5e5就可以过了,用的刘汝佳蓝书模板 &代码: #include & ...

  5. 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 ...

  6. 算法复习——trie树(poj2001)

    题目: 题目描述 给出 n 个单词(1<=n<=1000),求出每个单词的非公共前缀,如果没有,则输出自己. 输入格式 输入 N 个单词,每行一个,每个单词都是由 1-20 个小写字母构成 ...

  7. hihoCoder #1014 : Trie树 [ Trie ]

    传送门 #1014 : Trie树 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho是一对好朋友,出生在信息化社会的他们对编程产生了莫大的兴趣,他们约定好互 ...

  8. 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 ...

  9. Wild Words

    poj1816:http://poj.org/problem?id=1816 题意:给你n个模板串,然后每个串除了字母,还有?或者*,?可以代替任何非空单个字符,*可以替代任何长度任何串,包括空字符串 ...

随机推荐

  1. ShareSDK for iOS 2.9.0已经公布

    ShareSDK for iOS v2.9.0已经公布,本次更新内容包含: 1.修复Facebook获取用户信息报错问题 2.修复Instagram在iPad上显示分享菜单错误问题,须要指定菜单容器. ...

  2. xtrabackup原理0

  3. python中文处理之encode/decode函数

    python中文处理相信迷惑过不少同学.下面说说python2/3的encode和decode函数. python2中,使用decode()和encode()来进行解码和编码,以unicode类型作为 ...

  4. 03 InnoDB锁问题

    InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我们先介绍一点背景知识 ...

  5. 使用ReactiveCocoa开发RSS阅读器

    目前已经完成的功能有对RSS的解析和Atom解析,RSS内容本地数据库存储和读取,抓取中状态进度展示,标记阅读状态,标记全部已读等.这些功能里我对一些异步操作产生的数据采用了ReactiveCocoa ...

  6. [课程相关]homework-03

    零.准备工作 这次的作业是结对编程,因为一些原因我们的队伍一共有三个人,成员为:梁杰.夏天晗.谢祖三.由于大家不在一个班,交流起来也不是特别方便,所以我们经过讨论决定三个人约一个时间在一起完成这次作业 ...

  7. Linux串口编程(转载)

    在嵌入式Linux中,串口是一个字设备,访问具体的串行端口的编程与读/写文件 的操作类似,只需打开相应的设备文件即可操作.串口编程特殊在于串 口通信时相关参数与属性的设置.嵌入式Linux的串口编程时 ...

  8. AI 对不起 我还爱着你

    艾弗森,对不起,我还爱着你.有时候我自己都不知道自己我怎么了,直到最后才发现,我还爱着你. 那天起,我认识了你,便一发不可收拾.这些天,谢谢你,似乎因为你的影响让我改变了,坚持了许多.致以至今我才发现 ...

  9. Servlet & JSP - Listener

    Servlet API 中的 6 个事件类 1. ServletContextEvent:该类表示上下文事件,当应用上下文对象发生改变,例如创建或销毁上下文对象时,将触发上下文事件. 2. Servl ...

  10. EF中"实体类型 XXXXX 不是当前上下文的模型的一部分。" 原因

    用T4模版生成的数据库映射文件.cs对应不上数据库的字段而引起的错误(我是修改了cs里面的属性),只要根据数据库字段,修改回来就OK.问题就解决了.