문제
세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다.
말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.
좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.
입력
첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1 ≤ R,C ≤ 20) 둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.
출력
첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.
예제 입력 1
2 4
CAAB
ADCB
예제 출력 1
3
예제 입력 2
3 6
HFDFFB
AJHGDH
DGAGEH
예제 출력 2
6
예제 입력 3
5 5
IEFCJ
FHFKC
FFALF
HFGCF
HMCHH
예제 출력 3
10
🎀 나의 풀이
# Pypy3로 제출시 통과
import sys
input=sys.stdin.readline
R, C=map(int, input().split()) # 세로, 가로
board=[input() for _ in range(R)]
length=1
ans=0
visit=[0]*26
dx=[0, 0, -1, 1]
dy=[1, -1, 0, 0]
def dfs(x, y, length) :
global ans
ans=max(length, ans)
for d in range(4) :
nx=dx[d]+x
ny=dy[d]+y
if 0 <= nx < R and 0 <= ny < C :
if not visit[ord(board[nx][ny])-ord('A')] :
visit[ord(board[nx][ny])-ord('A')]=1
dfs(nx, ny, length+1)
visit[ord(board[nx][ny])-ord('A')]=0
return ans
visit[ord(board[0][0])-ord('A')]=1
print(dfs(0, 0, length))
pypy3로 제출해야 통과
다른 언어들은 백트래킹으로 구현하면 통과되던데...
왜 파이썬으로 백트래킹 구현하니까 시간초과야???
파이썬이 느리긴 하구나,,
# 시간초과
import sys
input=sys.stdin.readline
R, C=map(int, input().split()) # 세로, 가로
board=[input() for _ in range(R)]
length=1
ans=0
visit=set(board[0][0])
dx=[0, 0, -1, 1]
dy=[1, -1, 0, 0]
def dfs(x, y) :
global length, ans
ans=max(length, ans)
for d in range(4) :
nx=dx[d]+x
ny=dy[d]+y
if 0 <= nx < R and 0 <= ny < C :
if board[nx][ny] not in visit :
visit.add(board[nx][ny])
length+=1
dfs(nx, ny)
visit.discard(board[nx][ny])
length-=1
return ans
print(dfs(0, 0))
처음에 작성한 코드
너무 쉽게 풀었다 했더니 시간초과 ㅠ.ㅠ
정답 비율이 29.112%인 이유가 있구나 😅
in 때문에 시간초과 나는건가?!
🐊 다른 사람 풀이
# https://devjin-blog.com/boj-1987-alphabet/
import sys
# 좌, 하, 우, 상
dx=[-1, 0, 1, 0]
dy=[0, -1, 0, 1]
def BFS(x, y) :
global answer
q=set([(x, y, board[x][y])])
while q :
x, y, ans=q.pop()
for i in range(4) :
nx=x+dx[i]
ny=y+dy[i]
if((0 <= nx < R) and (0 <= ny < C) and (board[nx][ny] not in ans)) :
q.add((nx, ny, ans+board[nx][ny]))
answer=max(answer, len(ans)+1)
R, C=map(int, sys.stdin.readline().split())
board=[list(sys.stdin.readline().strip()) for _ in range(R)]
answer=1
BFS(0, 0)
print(answer)
이 문제는 dfs보다 bfs가 더 적합한가보다.
파이썬으로 제출해도 통과한다.
하긴 dfs로 한 곳을 골라서 막힐 때까지 갔다가 다시 되돌아오는 것보다 더 낫다.
근데 보통 bfs 구현할 때 deque를 많이 쓰는데 이 분은 set으로 구현함.
중복을 허용하지 않으려는 의도인 것 같다.
import java.util.*;
import java.io.*;
public class Main{
static int R, C, ans;
static char[][] board;
static int[][] visit;
static final int[] dx={0, 0, 1, -1};
static final int[] dy={1, -1, 0, 0};
public static void main(String[] args) throws Exception{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
R=Integer.parseInt(st.nextToken());
C=Integer.parseInt(st.nextToken());
board=new char[R][C];
visit=new int[R][C];
for(int i=0; i<R; i++){
board[i]=br.readLine().toCharArray();
}
dfs(0, 0, 1 << board[0][0]-'A', 1);
System.out.println(ans);
}
public static void dfs(int x, int y, int bit, int cnt){
if(visit[x][y] == bit) return;
visit[x][y]=bit;
ans=Math.max(ans, cnt);
for(int i=0; i<4; i++){
int nx=x+dx[i];
int ny=y+dy[i];
if(nx<0 || ny<0 || nx==R || ny==C || (bit&(1<<board[nx][ny]-'A')) != 0) continue;
dfs(nx, ny, bit | (1<<board[nx][ny]-'A'), cnt+1);
}
}
}
비트마스크로 문자 포함 여부를 판단한다.
신박한 풀이다👍
visit 안 써도 통과한다.
하지만, 성능 차이가 있기 때문에 visit을 쓰는 게 더 빠름
문제 출처 👉 백준
'coding test' 카테고리의 다른 글
[파이썬, Java] 11403. 경로 찾기 (0) | 2021.10.08 |
---|---|
[파이썬, Java] 1707. 이분 그래프 (0) | 2021.10.07 |
[파이썬] 2098. 외판원순회 (0) | 2021.10.06 |
[파이썬] 11723. 집합 (0) | 2021.10.04 |
[파이썬, Java] 1102. 발전소 (0) | 2021.10.03 |