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