www.acmicpc.net/problem/13460

 

13460번: 구슬 탈출 2

첫 번째 줄에는 보드의 세로, 가로 크기를 의미하는 두 정수 N, M (3 ≤ N, M ≤ 10)이 주어진다. 다음 N개의 줄에 보드의 모양을 나타내는 길이 M의 문자열이 주어진다. 이 문자열은 '.', '#', 'O', 'R', 'B'

www.acmicpc.net

보드 안에 두 개(R, B) 구슬이 있고, 최소 몇 번 만에 빨간 구슬을 구멍(O)을 통해 빼낼 수 있는지 출력하는 문제입니다.

만약, 10번 이하로 움직여서 빨간 구슬을 구멍을 통해 빼낼 수 없으면 -1을 출력합니다.

음... 이 문제도 일단 처음 접근은 X, Y 보드에 최소 이동을 구하는 문제이니 너비우선탐색(BFS)을 생각해봤습니다. 

다만 한 번에 한칸이 움직이는 것이 아닌 보드의 끝까지 이동을 하는 방식이며,

B는 구멍을 통해 나가면 안 되는 조건이 추가되었습니다.

이번엔 파이썬(Python)으로 문제를 풀어볼게요.

 

1. 먼저 입력을 받고, 구슬을 넣고 돌릴 보드 생성, 그리고 visit node를 구성합니다.

visit node에는 빨간 공의 x, y좌표 파란 공의 x, y 좌표를 위해 4차원으로 선언합니다.

1
2
3
4
n, m = map(int, input().split())
 
board = []
visit = [[[[False* m for i in range(n)] for i in range(m)] for i in range(n)]
cs

 

2. 그런 다음 움직일 dx, dy 좌표를 정의하고 board에 문제 입력을 받아줍니다.

그 후 BFS를 수행하기 위해서 파이썬에서 사용하는 deque를 사용해주고

q.append를 사용해서 빨간 공의 현재 좌표, 파란 공의 현재 좌표, 그다음 우리가 알고자 하는 빨간 공의

움직인 횟수를 넣어줍니다. 한 번은 반드시 움직이므로 1을 넣어주고 시작합니다.

그리고 BFS알고리즘을 만들어주면 되겠죠

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dx = [1-100]
dy = [00-11]
 
for i in range(n):
    t = list(input())
    board.append(t)
    for j in range(m):
        if t[j] == "R":
            rx, ry = i, j
        if t[j] == "B":
            bx, by = i, j
 
= deque()
q.append([rx,ry,bx,by,1])
visit[rx][ry][bx][by] = True            
bfs()
cs

 

3. 공들이 움직이는 조건 move() 함수 만들어서 체크 

이번 조건은 공이 보드에서 한 번에 한 칸 움직이는 것이 아닌 기울기를 이용해 벽 끝까지 도달하거나

O구멍에 빠지는 조건입니다. 따라서 벽끝까지 도달하거나 O구멍에 빠질 때까지 계속 이동시켜주어야겠죠

그리고 마지막으로 변수 c를 만들어 각 공들이 몇 칸을 움직였는지 체크해 줍니다.

만약 # . . . R . B# 였다면 이것을 왼쪽으로 기울였을 때, R공은 3칸, B공은 5칸 움직이게 되는 것이죠.

움직임 값을 이용해 R이 더 왼쪽에 있는지 B가 더 왼쪽에 있는지 확인을 할 수 있고, B의 좌표를

한 칸 오른쪽으로 밀어주면서 결과적으로

#R B . . . . .# 와 같은 배치로 바뀌어질 것입니다.

1
2
3
4
5
6
7
def move(nx,ny,dx,dy):
    c=0
    while board[nx][ny] !='O' and board[nx+dx][ny+dy] !='#':
        nx += dx
        ny += dy
        c +=1
    return nx,ny,c
cs

 

4. BFS 알고리즘으로 결과 도출

q가 비워질 때까지 while문을 돌리고 q를 꺼내서 현재 좌표와 움직인 횟수를 저장합니다.

그 움직인 횟수가 10회 이상이면 while 문을 빠져나가 24번 라인의 print(-1)을 출력하고요.

그게 아니라면 4방향 좌표에 대한 for문을 돌리고

그 안에서 move() 함수를 만들어 공들이 움직일 수 있는지 구멍에 들어가는지 체크를 하게 됩니다.

움직일 수 있는 조건이면, 움직일 새로운 좌표를 정의합니다.

9번째 줄에서 만약 파란 공이 O구멍에 있지 않을 때,

10번처럼 빨간 공은 O구멍에 도달했다면 조건 성공이므로 그때의 cnt 값을 출력합니다.

그게 아니면,  move () 함수를 통해 얻어 냈던 rc, bc 값을 확인해서 빨간공과 파란공의 좌표를

재배치 시켜줍니다.

그 후 visit 노드를 체크해서 방문한 적이 없다면 true를 넣어주고

그 다음 각 공의 좌표와 이동 횟수를 추가 해주면 이 알고리즘은 완성이 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def bfs():
    while q:
        rx,ry,bx,by,cnt = q.popleft()
        if cnt >10:
            break
        for i in range(4):
            nrx,nry,rc = move(rx,ry,dx[i],dy[i])
            nbx,nby,bc = move(bx,by,dx[i],dy[i])
            if board[nbx][nby] !='O':
                if board[nrx][nry] =='O':
                    print(cnt)
                    return
                if nrx == nbx and nry == nby:
                    if rc > bc:
                        nrx -=dx[i]
                        nry -=dy[i]
                    else:
                        nbx -=dx[i]
                        nby -=dy[i]
                
                if not visit[nrx][nry][nbx][nby] :
                    visit[nrx][nry][nbx][nby] = True
                    q.append([nrx,nry,nbx,nby,cnt+1])
    print(-1)
cs

 

다음은 소스코드 전체입니다.

 

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
from collections import deque
 
 
n, m = map(int, input().split())
dx = [1-100]
dy = [00-11]
visit = [[[[False* m for i in range(n)] for i in range(m)] for i in range(n)]
board = []
 
def move(nx,ny,dx,dy):
    c=0
    while board[nx][ny] !='O' and board[nx+dx][ny+dy] !='#':
        nx += dx
        ny += dy
        c +=1
    return nx,ny,c
 
def bfs():
    while q:
        rx,ry,bx,by,cnt = q.popleft()
        if cnt >10:
            break
        for i in range(4):
            nrx,nry,rc = move(rx,ry,dx[i],dy[i])
            nbx,nby,bc = move(bx,by,dx[i],dy[i])
            if board[nbx][nby] !='O':
                if board[nrx][nry] =='O':
                    print(cnt)
                    return
                if nrx == nbx and nry == nby:
                    if rc > bc:
                        nrx -=dx[i]
                        nry -=dy[i]
                    else:
                        nbx -=dx[i]
                        nby -=dy[i]
                
                if not visit[nrx][nry][nbx][nby] :
                    visit[nrx][nry][nbx][nby] = True
                    q.append([nrx,nry,nbx,nby,cnt+1])
    print(-1)
 
for i in range(n):
    t = list(input())
    board.append(t)
    for j in range(m):
        if t[j] == "R":
            rx, ry = i, j
        if t[j] == "B":
            bx, by = i, j
 
= deque()
q.append([rx,ry,bx,by,1])
visit[rx][ry][bx][by] = True
bfs()
 
cs

 

도움이 되셨다면 구독 좋아요? 눌러주세요~

'코딩 탐구 > 삼성 코딩테스트' 카테고리의 다른 글

백준 17170 파이프 옮기기1  (0) 2021.01.14

웹페이지나 개인 블로그에서 유튜브 영상링크를 넣는 방법입니다.

요즘 티스토리나, 네이버 블로그는 주로 링크만 해도 바로 유튜브 영상이 삽입되는데요.

블로그 유튜브링크를 걸었는데 가끔 영상이 제대로 뜨지않고 회색박스만 표시되는등의 오류로 안될 때,

쉽게 해결 할 수 있는 방법이에요.

이 방법은 HTML 에디터를 지원하는 곳에서 다 적용가능하니 한 번 익혀두면 좋을 것 같아요! 

아주아주 쉬워요! 바로 시작해볼게요.

1. 링크를 띄우고 싶은 유튜브를 찾는다. 

    BTS 의 Dynamite를 예로 들어볼게요. 유튜브에서 링크할 영상을 찾은다음, 하단의 공유버튼을 찾아주세요.

2. 영상 하단에 공유버튼을 누르고 퍼가기 클릭

위 사진에 공유 버튼을 누르면, 퍼가기가 있어요 이것을 클릭

3. 동영상 퍼가기 밑에 복사버튼을 눌러서 http 소스코드를 복사

퍼가기를 누르면 아래처럼 동영상 퍼가기가 보이고, 오른쪽에 아래 복사버튼을 눌러주세요.

시작시간을 체크하고 시간을 정하면 내가 플레이하고싶은 분초대에서 시작 할 수있게 링크를 걸수도 있어요!

4. 글작성 중 상단의 기본모드를 HTML 로 전환해주고 원하는 곳에 붙여넣기를 해준다.

 

5. 그리고 HTML모드에서 주소를 붙여넣기만 해주면 끝!!

 

BTS - Dynamite 링크입니다. 영상이 제대로 삽입 되었는지 확인만하면 끝이에요~!

 

문제 출처: www.acmicpc.net/problem/17070

 

17070번: 파이프 옮기기 1

유현이가 새 집으로 이사했다. 새 집의 크기는 N×N의 격자판으로 나타낼 수 있고, 1×1크기의 정사각형 칸으로 나누어져 있다. 각각의 칸은 (r, c)로 나타낼 수 있다. 여기서 r은 행의 번호, c는 열의

www.acmicpc.net

삼성 코딩테스트 대비를 위해서라면 기출문제를 푸는게 직빵이겠죠?

한 번, 풀어보고자 하는데 일단 알고리즘 분류는 아래처럼 그래프, DP로 분류 되어있네요.

저는!

보드판만 보면 왜 본능적으로 BFS(Breath First Search)가 떠오르는지.. BFS로 문제를 풀어보려 합니다.

일단 main 부터,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{
    cin >> d;
    board.assign(d, vector<int>(d, 0));
    for (int i = 0; i < d; i++) {
        for (int j = 0; j < d; j++) {
            int tmp;
            cin >> tmp;
            board[i][j] = tmp;
        }
    }
    bfs();
    cout << cnt;
}
cs

vector를 이용해서 입력 받은 사이즈만큼 초기화를 하고, bfs함수를 호출하고

거기서 update된 cnt 값을 출력하는 식으로 작성을 하겠습니다.

다음은, 알고리즘 파트인 BFS 함수를 보시죠.

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
void bfs(void) {
    queue<pair<pair<int,int>,int> > q;
    q.push(make_pair(make_pair(0,1),0));
    
    while (!q.empty()) {
        pair<pair<intint>int> pd = q.front();
        q.pop();
        int x = pd.first.first;
        int y = pd.first.second;
        int di = pd.second;
 
        for (int i = 0; i < 3; i++) {
            if ((di == 0 && i != 1|| (di == 1 && i != 0||di==2) {
                int nx = x + dx[i];
                int ny = y + dy[i];
 
                if (move(nx, ny, i)) {
                    if (nx == (d - 1&& ny == (d - 1)) cnt++;
                    q.push(make_pair(make_pair(nx, ny), i));
                }
            }
        }
 
    }
 
}
cs

BFS는 공식처럼 외워 버려요!! 그런데 BFS에서 보통 쓰는 visit node 를 사용하지 않았어요. 

이유는 경우의 수를 구하는 문제고, 게다가 방향은 언제나 오른쪽 밑으로 내려가기 때문이죠.

그래서 visit 여부를 체크 할 필요가 없다고 생각했어요.

공식처럼 전해지는 BFS 알고리즘 보다 쉬운 형태라고 볼 수 있어요.

그래서 처음 Queue를 Push할 때, 좌표값인 x, y값과 ㅡ,ㅣ,\를 각각 Index번호로 같이 Push 합니다.

파이프는 직각 형태로는 이동을 할 수 없으니, ㅡ 형태일때는 ㅣ 형태가 오지 않도록,

또 반대의 경우도 마찬가지고요. 그것을 13번 째 줄에서 체크를 하고요.

move라는 파이프가 이동할 수 있는 경우의 수를 체크하고 이동 가능하면, 이동하면서 이동할 좌표를 

Queue에 Push하면 끝입니다. 

 

아래는, 전체 소스코드 입니다!

 

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
65
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
vector<vector<int> > board;
int d;
int dx[3= { 0,1,1 };
int dy[3= { 1,0,1 };
int cnt;
 
int move(int x, int y,int idx) {
    if (x < d && y < d) {
        if (idx == 2) {
            if (board[x][y] | board[x][y - 1| board[x - 1][y]) return 0;
        }
        else {
            if (board[x][y]) return 0;
        }
        return 1;
    }
    return 0;
}
 
void bfs(void) {
    queue<pair<pair<int,int>,int> > q;
    q.push(make_pair(make_pair(0,1),0));
    
    while (!q.empty()) {
        pair<pair<intint>int> pd = q.front();
        q.pop();
        int x = pd.first.first;
        int y = pd.first.second;
        int di = pd.second;
 
        for (int i = 0; i < 3; i++) {
            if ((di == 0 && i != 1|| (di == 1 && i != 0||di==2) {
                int nx = x + dx[i];
                int ny = y + dy[i];
 
                if (move(nx, ny, i)) {
                    if (nx == (d - 1&& ny == (d - 1)) cnt++;
                    q.push(make_pair(make_pair(nx, ny), i));
                }
            }
        }
 
    }
 
}
int main()
{
    cin >> d;
    board.assign(d, vector<int>(d, 0));
    for (int i = 0; i < d; i++) {
        for (int j = 0; j < d; j++) {
            int tmp;
            cin >> tmp;
            board[i][j] = tmp;
        }
    }
    bfs();
    cout << cnt;
}
 
cs

 

'코딩 탐구 > 삼성 코딩테스트' 카테고리의 다른 글

백준 13460 구슬 탈출 2  (0) 2021.01.17

15년간 자취생활을 하면 서, 이사만 8번은 한 것 같네요.

자취생이고 짐도 많이 없다보니 이사 업체를 부르기엔 이사 비용이 너무 아까웠습니다.

친구나 지인찬스를 쓰며 자장면 한 끼 값으로 이사 한 적도 있지만, 매번 도움 받을 수도 없는 것이고...

그러다보니 저렴하게 이사할 수 있는 방법을 연구하였고, 세 가지 방법을 소개 할까 해요.

제가 겪었던 이사 방법 그리고 대략적인 이사 비용을 정리 해볼게요!


1. 짐도 적고, 이사 거리가 4KM 이내 일 때 (서울 기준) 면허증이 있다.

  • 난 두 시간 안에 승부를 본다 - 쏘카, 그린카 등 차량공유 서비스를 이용한 이사 방법

  쏘카, 그린카등 카쉐어링 (운전면허증이 있어야해요)

보통 자취생은 어느정도 옵션이 있는 곳으로 이사 가죠. 그럼 보통 짐의 대다수는 옷, 이불, 컴퓨터, 의자, 식기, 책상 정도에요.


이런 분들에게 카 쉐어링 서비스를 이용하여 이사 하는게 최고 저렴 할 것 같아요. (약간 의도와는 다른 이용이지만?)

그 중에 제일 저렴한 기아차 "레이"를 이용하여 이사하면 정말 저렴하게 이사가 가능하답니다.

서울 기준으로 4km 정도면 15분 안에 목적지 도달이 가능해요. 그래서 레이를 두번 왕복한다는 느낌으로.. 방법을 적어 볼게요.

  1. 먼저 이사하기 전 짐을 다 쌓아 놓는다. 바로 차에 실을 수 있는 정도로 알맞게 포장하고 문 앞에 준비 해 놓는다.
  2. 쏘카(그린카)를 이용해 차를 빌린다. 
  3. 차를 집 앞에 주차하고 최대한 빨리 짐을 싣고 꽉꽉 채우고 출발한다. 
  4. 목적지(새집)에 도착하면, 짐을 빠르게 내린다.
  5. 다시 이전 집으로 돌아와 남은 짐을 다시 빠르게 싣고 출발한다.
  6. 목적지에 도착하여 짐을 빠르게 내린다.
  7. 차를 반납한다. 돌아와서 짐을 정리한다.

 이렇게 2시간 레이를 대여해서 이사 비용은.. 대략 14000원!!!

이사하다가 대여 시간이 초과되어도 그렇게 많은 비용은 발생하지 않으니까, 빠르게 행동하게 침착하게 안전하게 이사하시는 게 좋습니다.

짐이 적당히 많지만, 용달을 부르기에 애매한 경우라면 "카니발" 차량을 대여해서 이사해보는 것도 좋을 것 같아요.

요금은 조금 더 들겠지만 용달은 최소 7만원 이상이니 대여비가 그 이하라면 추천 드리고 싶어요.


2.  짐도 적고, 이사 거리는 수도권인데... 면허증이 없네...

  • 퀵서비스 이사도 가능하다!!

만약 짐이 큰 박스로 3-4개 정도 나오는데, 옮길 방법이 없을 때 쓰는 방법입니다.

다마스 퀵서비스를 이용하면 저렴하게 이용할 수 있어요.

네이버 검색창에 "다마스퀵"을 칩니다.

아마도 지역 퀵서비스도 있을 것이고, 이렇게 인터넷을 통한 견적 상담도 받을 수 있을 거에요.

경험상 이것도 싸게는 4만원 부터 저렴하게 이용이 가능했어요. 

짐이 박스로 3박스 나왔었고,  심지어 경기도 남부에서 서울 한복판으로 이사였는데도 

4만원에 다마스를 타고 이삿짐과 함께 제 몸까지 이사를 해주었답니다. 

퀵서비스 이사도 적극 추천합니다.


3. 짐이 많으면 어쩔 수 없다. 면허증도 없다. 용달차를 부르자.

  • 이사 어플 (짐싸 , 이사모아, 짐카 등)로 최소 견적 받고 이사하기
인터넷으로 용달차를 검색하면, 뭔가 광고가... 저는 쉽게 문의하기가 꺼려지더라고요..

 광고인데 들어가기 싫어진다...

그래서 어떤 방법이 있을까 찾아봤더니, 이사 어플이 엄청 활성화 되어 있고 이용하기 쉽게 되어있는 것을 확인 했습니다.

바로 이사 어플이죠.(짐싸 , 이사모아, 짐카 등). 구글 플레이스토어나, 애플 앱스토어에서 쉽게 다운 받을 수 있습니다.

                             

1. 구글 플레이스토어에서 짐싸를 다운받고                      견적을 알아본다. 


2. 침대 행거 테이블 등등의 가전제품의 수량을 체크하고 박스 개수도 체크한다.


3. 각 가구에 대한 상세 내역을 입력하고 이사일과 이사 장소를 선택 한다.


 기사님 선택하면 끝!

이제 끝입니다. 기사님들이 견적을 올려주게 되고 기사님들끼리는 견적가를 몰라요.

평점과 리뷰와 가격을 확인해서 기사님을 선택하면, 기사님이랑 매칭이 되고 기사님한테서 연락이 올 거에요.

연락을 받고 상세한 사항을 조율하고 이사를 하면 됩니다.


경험상 짐도 내가 다 옮기고(용달과 운전만 지원), 짐도 그렇게 많지 않은 옵션일 때 견적이 70,000 정도 나왔어요.(동작구 > 노원구)

용달 기사님을 지원 받아서 이사하는 옵션도 있고, 포장이사 옵션도 있어요 (물론 그러면 비싸지겠죠~)


이상 3가지 자취생 이사 방법을 알아보았습니다.

가족이나 지인 도움으로 이사하기 힘든 자취생분들께 도움이 되었으면 좋겠네요! 








+ Recent posts