• 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
  • 相关阅读:
    sql server数据库备份与复制(1):通过复制.mdf和.ldf文件实现数据转移
    SQL SERVER数据库备份与复制(4):让SQL SERVER自动备份方法一
    js 日历控件
    SQL SERVERa数据备份与复制(2):直接复制MDF文件和使用SQL的备份之间的区别
    mysql 插入中文乱码解决方案
    sql server数据库注意点
    SQL SERVERR数据库备份与复制(5):自动备份的SP
    mysql数据备份或转移(1)——通过数据复制实现转移
    SQL Server数据库备份与复制(3):从备份到转移的几种方法方法
    SQLSERVER数据存储内幕
  • 原文地址:https://www.cnblogs.com/dengyaolong/p/3679922.html
Copyright © 2020-2023  润新知