【2018 SWERC - C 】Crosswords【字典树、暴力搜索】

题意

给出 AA 个长度为 NN 的字符串,BB 个长度为 MM 的字符串,将长度为 NN 的字符串竖直摆放,长度为 MM 的字符串水平摆放,问能形成多少个 NMN*M 的矩阵。(2N,M4,1AB1008016)(2\leq N,M\leq 4,1\leq A*B\leq 1008016)

如下图所示,says,area,testsays,area,test 为长度为 MM 的字符串,sat,are,yes,satsat,are,yes,sat 为长度为 NN 的字符串。
在这里插入图片描述


思路

比赛的时候觉得这题很好玩,因为题意有点绕,NNMM 老是分不太清。

彻底搞清楚题意后,也没多少时间了,再加上这题过的人比较少,以为是道比较难的题,就没细想…(不过这类数独题第一反应的确应该是搜索…

赛后看了眼别人的代码,发现好暴力好简单…T^T

话不多说,做法就是维护长度为 NN 的字符串的字典树,以及长度为 MM 的字符串的字典树,枚举每一个格子填的字符,从左到右,从上到下依次进行暴力匹配,匹配成功则 ans=ans+1ans=ans+1

具体细节可以看看下面的代码,还是不太难理解的。

反思一下,如果早点看懂这道题,正确的思考方式如下:

  1. 类似数独,感觉是考察搜索
  2. 怎么搜呢?矩形也不大,要不直接枚举每个节点的字符算了,暴力一发试试水
  3. 怎么枚举呢?一次性枚举全部肯定是欠 T,要不按顺序从左到右,从上到下枚举试试
  4. 好像有点道理,那怎么判断当前对不对呢?
  5. emmmemmm,涉及字符匹配的数据结构,我想想… KMP?KMP? 88
  6. 噢!字典树!妙啊,冲冲冲!
  7. 恭喜您获得了绿油油的 AcceptedAccepted

代码

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i = a; i <= b; i++)
const int N = 1e6+10;
using namespace std;

struct Trie{
	int tot, root, ch[N][30], pre[N];
	Trie() {root = tot = 0;}
	void insert(char *str){
		int cur = root;
		for(int i = 0; str[i]; i++){
			int x = str[i]-'a';
			if(ch[cur][x] == 0) ch[cur][x] = ++tot, pre[tot] = cur;
			cur = ch[cur][x];
		}
	}
}tre1, tre2;

int n,m,a,b,ans,pos1[10],pos2[10];
char s[N];

void dfs(int id){
	if(id == n * m - 1) {ans++; return;} 
	id++; int row = id / m, col = id % m;
	rep(i,0,25){
		if(tre1.ch[pos1[col]][i] && tre2.ch[pos2[row]][i]){
			pos1[col] = tre1.ch[pos1[col]][i];
			pos2[row] = tre2.ch[pos2[row]][i];
			dfs(id);
			pos1[col] = tre1.pre[pos1[col]];
			pos2[row] = tre2.pre[pos2[row]];
		}
	}
}

int main()
{
	scanf("%d%d",&n,&a);
	scanf("%d%d",&m,&b);
	rep(i,1,a) scanf("%s",s), tre1.insert(s);
	rep(i,1,b) scanf("%s",s), tre2.insert(s);
	dfs(-1);
	printf("%d\n", ans);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章