zoukankan      html  css  js  c++  java
  • 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。

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

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

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

      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(0){
     16         memset(child,0,sizeof(child)); //初始化节点
     17     }
     18     
     19 };
     20 int RR[10200],CC[10200];
     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=0;i<Size;i++)
     35             root.child[i]=0;
     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]==0){
     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]==0){
     92                 
     93                 RR[cur->id]=r;
     94                 CC[cur->id]=c;
     95             }
     96         }
     97         
     98     }
     99     
    100     
    101     
    102     //重载c风格
    103     void find(const char *str,int r,int c){
    104         
    105         find(str,str+strlen(str),r,c);
    106     }
    107     
    108     
    109     
    110     
    111     
    112 private:
    113     
    114     
    115     //清空
    116     void clear_node(node_type cur){
    117         for(int i=0;i<Size;i++){
    118             if(cur.child[i]==0)continue; //不存在
    119             clear_node(*cur.child[i]);
    120             delete cur.childe[i];
    121             cur.child[i]=0;
    122             if(--cur.node==0) break; //没有节点了
    123             
    124         }
    125         
    126     }
    127     
    128     
    129     //
    130     node_type root;
    131     //字符转索引,类似hash
    132     Index index;
    133     
    134 };
    135 
    136 class IndexClass{
    137 public:
    138     int operator[](const char key){
    139         return key%26; //一个映射
    140         
    141     }
    142     
    143 };
    144 char cc[501][501];
    145 char s[21];
    146 int mini(int a,int b){
    147     return a>b?b:a;
    148 }
    149 int main(){
    150     trie<26,IndexClass> t;
    151     int R,C,i,j,l,ed;
    152     scanf("%d%d",&R,&C);
    153     getchar(); //读掉回车
    154     for( i=0;i<R;i++)
    155     {
    156         
    157         gets(cc[i]);
    158     }
    159         
    160     int N=0;
    161     while(gets(s)&&s[0]!='-'){
    162         if(s[0]){
    163             t.insert(s,N);   //用每一个要查找的单词构树
    164                 N++;
    165         }
    166             
    167     }
    168     
    169         for(i=0;i<R;i++)
    170             for( j=0;j<C;j++){
    171                 //向下
    172                 memset(s,0,sizeof(s));
    173                 if(i+20<R) ed=20;
    174                 else ed=R-i;
    175                 for(l=0;l<ed;l++){
    176                     s[l]=cc[i+l][j];
    177                     
    178                 }
    179             
    180                 t.find(s,i+1,j+1);
    181                 //向右
    182                 memset(s,0,sizeof(s));
    183                 if(j+20<C) ed=20;
    184                 else ed=C-j;
    185                 for( l=0;l<ed;l++){
    186                     s[l]=cc[i][j+l];
    187                     
    188                 }
    189                 
    190                 t.find(s,i+1,j+1);
    191 
    192                 //右下
    193                 memset(s,0,sizeof(s));
    194                 if(i+20<R&&j+20<C) ed=20;
    195                 else ed=mini(C-j,R-i);
    196                 for( l=0;l<ed;l++){
    197                     s[l]=cc[i+l][j+l];
    198                     
    199                 }
    200             
    201                 t.find(s,i+1,j+1);
    202                 
    203             }
    204             
    205             for( i=0;i<N;i++){
    206                 
    207                 if(RR[i]!=0||CC[i]!=0)
    208                     printf("%d %d
    ",RR[i]-1,CC[i]-1);
    209                 else puts("-1 -1");
    210             }
    211             
    212                         
    213             
    214             return 0;
    215                         
    216 }
    View Code
  • 相关阅读:
    RecyclerView 数据刷新的几种方式 局部刷新 notify MD
    【图片】批量获取几万张图片
    RV BaseRecyclerViewAdapterHelper 总结 MD
    RecyclerView.ItemDecoration 间隔线
    Kotlin【简介】Android开发 配置 扩展
    Kotlin 特性 语法糖 优势 扩展 高阶 MD
    一个十分简洁实用的MD风格的UI主框架
    折叠伸缩工具栏 CollapsingToolbarLayout
    FloatingActionButton FAB 悬浮按钮
    Glide Picasso Fresco UIL 图片框架 缓存 MD
  • 原文地址:https://www.cnblogs.com/dengyaolong/p/3679922.html
Copyright © 2011-2022 走看看