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个模板串,然后每个串除了字母,还有?或者*,?可以代替任何非空单个字符,*可以替代任何长度任何串,包括空字符串 ...
随机推荐
- SQL Server中DML语句要申请的锁
对于select语句: 1.当採用表扫描时,会直接锁定page,而不是锁定详细的某条记录,所以会有这些锁: A.数据库S锁 B.表的IS锁 C.页的S锁 2.当採用索引来查找数据时,会锁定详细的记录, ...
- 解决PowerDesigner 反向工程没有注释(备注)
本文转载自:http://www.cnblogs.com/zhangxb/archive/2012/04/20/2458898.html 1. 列注释 原来代码: {OWNER, TABLE, S, ...
- 关于flash player debugger 无法弹窗报错的解决办法
第一个是IE的插件, Download the Windows Flash Player 10.2 ActiveX control content debugger (for IE) (EXE, 2. ...
- redo log write和flush
http://bbs.chinaunix.net/thread-1753130-1-1.html 在事务提交时innobase会调用ha_innodb.cc 中的innobase_commit,而in ...
- debian分区方案(就这个看着靠谱点)转
debian分区方案(就这个看着靠谱点)转 桌面系统/tmp 1G (仅用作临时文件) ext3/ext4/home Max (用户目录数据) ext3/ext4/usr 20G (软件) ext3/ ...
- 聊聊 #pragma 和 // MARK:
我去,就这两个东西还要讲?是OC或Swift开发人员都知道是怎么回事好吗?不就是用来标记和分组代码的吗?难道还有别的装逼技能? 当然,其实问大部分人说这两个是什么作用,或者是除了这两个还知道什么的情况 ...
- Android快速开发框架ZBLibrary源码分享
坐标标准库ZBLibrary,是一个MVP架构的Android快速开发框架,提供一套开发标准(UI,Data,Listener)以及模板和工具类并规范代码. 封装层级少,简单高效兼容性好.Androi ...
- 分享一个java线程专栏
专栏 : java线程基础 转载自 http://blog.csdn.net/column/details/yinwenjiethread.html 专栏内容: 1.线程基础:线程(1)--操作系统和 ...
- Windows Azure 微软公有云体验(二) 存储成本比较分析
Windows Azure 微软公有云已经登陆中国有一段时间了,现在是处于试用阶段,Windows Azure的使用将会给管理信息系统的开发.运行.维护带来什么样的新体验呢? Windows Azur ...
- linux-redhat5找回root密码
我在虚拟机里装了个redhat(RedhatEnterpriseLinuxASv5.4-x64),也不经常用,偶尔进去用用吧,又把密码忘记了,哎...脑子不好使啊 不知道像ubuntu是不是一样的,还 ...