【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章