문제
https://www.acmicpc.net/problem/20166
문제해설
격자안에 문자가 적혀있다.
격자안을 이동하며 방문했던 문자들을 이어서 문자열을 만든다.
이동할 수 있는 범위는 상하좌우, 4방향의 대각선이다.
한번 방문했던 곳도 다시 방문할 수 있다.
신이 만든 문자열 k개가 주어지고
이동해서 만들어진 문자열이 신이 만든 문자열과 같을 때 그 경우의 수를 구하면 된다.
문제풀이
단순 dfs로 풀기에는 시간초과가 예상되었다.
왜냐하면 주어지는 문자열이 최대 1000개이기 때문이다.
그래서 map을 사용해서 비교할 문자열을 저장하였다.
map<string, int>
이런식으로 만들어서
키값으로 문자열을, value값으로 경우의 수를 저장할 것이다.
dfs를 돌며 만들어진 문자열이 주어진 문자열에 있는지 map의 find함수를 써서 찾았다.
만약 있다면 경우의 수를 ++해주었다.
5자리를 넘어가는 문자열이 없기때문에 5를 넘어가면 return을 했다.
그리고 한가지 더 주의할 점이 주어진 문자열을 따로 벡터같은 곳에 저장해야한다.
왜냐하면 동일한 문자열이 주어질 수도 있다고 했기 때문이다.
격자의 크기만큼 dfs를 수행한 뒤
map에 저장된 주어진 문자열들의 value값들을 출력하면 된다.
전체코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
int n, m, k;
int dx[] = { 0,0,-1,1,1,1,-1,-1 };
int dy[] = { 1,-1,0,0,1,-1,1,-1 };
vector<vector<char>>arr;
map<string, int>res;
string tmp;
void dfs(int x, int y) {
if (tmp.length() > 5) return;
auto iter = res.find(tmp);
if (iter != res.end()) {
iter->second++;
}
for (int i = 0; i < 8; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx < 0) nx = n - 1;
if (nx >= n) nx = 0;
if (ny < 0) ny = m - 1;
if (ny >= m) ny = 0;
tmp += arr[nx][ny];
dfs(nx, ny);
tmp.pop_back();
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
cin >> n >> m >> k;
arr.resize(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
char x; cin >> x;
arr[i].push_back(x);
}
}
vector<string>god;
for (int i = 0; i < k; i++) {
string x; cin >> x;
god.push_back(x);
res.insert({ x,0 });
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
tmp.push_back(arr[i][j]);
dfs(i, j);
tmp.clear();
}
}
for (int i = 0; i < k; i++)
cout << res[god[i]] << "\n";
return 0;
}