문제:

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다.

말은 상하좌우로 인접한 네 칸 중의 한 칸으로 이동할 수 있는데, 새로 이동한 칸에 적혀 있는 알파벳은 지금까지 지나온 모든 칸에 적혀 있는 알파벳과는 달라야 한다. 즉, 같은 알파벳이 적힌 칸을 두 번 지날 수 없다.

좌측 상단에서 시작해서, 말이 최대한 몇 칸을 지날 수 있는지를 구하는 프로그램을 작성하시오. 말이 지나는 칸은 좌측 상단의 칸도 포함된다.

입력:

첫째 줄에 R과 C가 빈칸을 사이에 두고 주어진다. (1 ≤ R,C ≤ 20) 둘째 줄부터 R개의 줄에 걸쳐서 보드에 적혀 있는 C개의 대문자 알파벳들이 빈칸 없이 주어진다.

출력:

첫째 줄에 말이 지날 수 있는 최대의 칸 수를 출력한다.

풀이방법:

dfs를 사용해서 이 문제를 풀 수 있다. dfs는 다음과 같이 구성되어 있다.

 

1. 한 점으로부터 시작해 상하좌우를 탐색한다. (처음은 1행 1열)

2. 상하좌우를 탐색할 때, 아직 방문하지 않았고, 처음보는 알파벳이라면 그 방향으로 다시 dfs를 탐색한다.

3. dfs를 시작하는 순간마다. 현재까지 가지고 있는 알파벳 수를 기억해서 최대 몇칸을 지날 수 있는지 확인한다.

4. 더 이상 이동하지 못하는 경우에 한 dfs를 빠져나오게 되며, 방문 기록과 알파벳 탐색 기록을 지운다.

 

최종적으로 3번을 통해 기록한 값을 출력하면 된다.

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
import sys
input = sys.stdin.readline
 
def dfs(x,y,tmp):
    global answer
    if answer < tmp:
        answer = tmp
    for i in range(4):
        nx = x + dx[i]
        ny = y + dy[i]
        if 0<=nx < R and 0 <=ny < C:
            if not history[ord(alphabet[nx][ny])-65and not visited[nx][ny]:
                history[ord(alphabet[nx][ny])-65= True
                visited[nx][ny] = 1
                dfs(nx,ny,tmp+1)
                visited[nx][ny] = 0
                history[ord(alphabet[nx][ny])-65= False
    
 
R,C = map(int,input().split())
alphabet = []
for _ in range(R):
    alphabet.append(list(input()))
visited = [[0 for _ in range(C)] for _ in range(R)]
dx = [-1,0,0,1]
dy = [0,-1,1,0]
 
history = [False]*26
visited[0][0= 1
history[ord(alphabet[0][0])-65= True
answer = 1
dfs(0,0,answer)
print(answer)
cs

문제링크:

https://www.acmicpc.net/problem/1987

 

1987번: 알파벳

세로 R칸, 가로 C칸으로 된 표 모양의 보드가 있다. 보드의 각 칸에는 대문자 알파벳이 하나씩 적혀 있고, 좌측 상단 칸 (1행 1열) 에는 말이 놓여 있다. 말은 상하좌우로 인접한 네 칸 중의 한 칸으

www.acmicpc.net

 

'Algorithm' 카테고리의 다른 글

[BOJ]11559. Puyo Puyo  (0) 2021.09.07
[BOJ]3190. 뱀  (0) 2021.08.19
[BOJ]1520. 내리막길  (0) 2021.08.17
[BOJ]14425. 문자열 집합  (0) 2021.06.24
[Programmers]Lv 1.완주하지 못한 선수  (0) 2019.02.17

문제:

눈금의 간격이 1인 M×N(M,N≤100)크기의 모눈종이가 있다. 이 모눈종이 위에 눈금에 맞추어 K개의 직사각형을 그릴 때, 이들 K개의 직사각형의 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어진다.

예를 들어 M=5, N=7 인 모눈종이 위에 <그림 1>과 같이 직사각형 3개를 그렸다면, 그 나머지 영역은 <그림 2>와 같이 3개의 분리된 영역으로 나누어지게 된다.

<그림 2>와 같이 분리된 세 영역의 넓이는 각각 1, 7, 13이 된다.

M, N과 K 그리고 K개의 직사각형의 좌표가 주어질 때, K개의 직사각형 내부를 제외한 나머지 부분이 몇 개의 분리된 영역으로 나누어지는지, 그리고 분리된 각 영역의 넓이가 얼마인지를 구하여 이를 출력하는 프로그램을 작성하시오.

입력:

첫째 줄에 M과 N, 그리고 K가 빈칸을 사이에 두고 차례로 주어진다. M, N, K는 모두 100 이하의 자연수이다. 둘째 줄부터 K개의 줄에는 한 줄에 하나씩 직사각형의 왼쪽 아래 꼭짓점의 x, y좌표값과 오른쪽 위 꼭짓점의 x, y좌표값이 빈칸을 사이에 두고 차례로 주어진다. 모눈종이의 왼쪽 아래 꼭짓점의 좌표는 (0,0)이고, 오른쪽 위 꼭짓점의 좌표는(N,M)이다. 입력되는 K개의 직사각형들이 모눈종이 전체를 채우는 경우는 없다.

출력:

첫째 줄에 분리되어 나누어지는 영역의 개수를 출력한다. 둘째 줄에는 각 영역의 넓이를 오름차순으로 정렬하여 빈칸을 사이에 두고 출력한다.

풀이방법:

 bfs를 사용하여 각 직사각형의 내부를 제외한 나머지 부분이 몇 개의 분리된 영역들의 넓이를 구한다. 전체 영역을 1로 초기화하고 직사각형의 꼭짓점을 입력값으로 받을 때, 내부 영역들을 0으로 재정의한다.

 이 과정을 모두 마친 뒤, (0,0)부터 bfs를 사용하여 분리된 영역들의 각 넓이를 구한다. 한 점으로부터 시작해 이동하면서 visited를 업데이트하여 중복적으로 이동하는 것을 막으며 더 이상 이동하지 못할 때, 하나의 분리된 영역의 넓이를 구한 것으로 파악한다.

 탐색하는 과정을 region이 1이고, 방문하지 않은(visited가 0인) 곳에 대해 반복적으로 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
dx = [-1,0,0,1]
dy = [0,1,-1,0]
 
def bfs(x,y):
    visited[y][x] = 1
    area = 1
    points = [(x,y)]
    while len(points):
        temp = []
        for point in points:
            x,y = point
            for i in range(4):
                nx = x+dx[i]
                ny = y+dy[i]
                if 0<= nx < n and 0<= ny < m:
                    if region[ny][nx]==1 and not visited[ny][nx]:
                        area+=1
                        visited[ny][nx]=1
                        temp.append((nx,ny))
        points = temp
    return area
                
 
m,n,k = map(int,input().split())
region = [[1 for _ in range(n)]for _ in range(m)]
visited = [[0 for _ in range(n)]for _ in range(m)]
 
for _ in range(k):
    x1,y1,x2,y2 = map(int,input().split())
    for x in range(x1,x2):
        for y in range(y1,y2):
            region[y][x] = 0
 
 
answers = []
for x in range(n):
    for y in range(m):
        if region[y][x] and not visited[y][x]:
            answer = bfs(x,y)
            answers.append(answer)
            
print(len(answers))
print(*sorted(answers))
cs

문제링크:

https://www.acmicpc.net/problem/2583

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1422. 숫자의 신  (0) 2021.05.25
[BOJ]15686. 치킨 배달  (0) 2021.05.20
[BOJ]3055. 탈출  (0) 2021.05.11
[BOJ]2630. 색종이 만들기  (0) 2021.04.29
[BOJ]3273. 두 수의 합  (0) 2021.04.27

문제:

사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제일 친한 친구인 비버의 굴로 가능한 빨리 도망가 홍수를 피하려고 한다.

티떱숲의 지도는 R행 C열로 이루어져 있다. 비어있는 곳은 '.'로 표시되어 있고, 물이 차있는 지역은 '*', 돌은 'X'로 표시되어 있다. 비버의 굴은 'D'로, 고슴도치의 위치는 'S'로 나타내어져 있다.

매 분마다 고슴도치는 현재 있는 칸과 인접한 네 칸 중 하나로 이동할 수 있다. (위, 아래, 오른쪽, 왼쪽) 물도 매 분마다 비어있는 칸으로 확장한다. 물이 있는 칸과 인접해있는 비어있는 칸(적어도 한 변을 공유)은 물이 차게 된다. 물과 고슴도치는 돌을 통과할 수 없다. 또, 고슴도치는 물로 차있는 구역으로 이동할 수 없고, 물도 비버의 소굴로 이동할 수 없다.

티떱숲의 지도가 주어졌을 때, 고슴도치가 안전하게 비버의 굴로 이동하기 위해 필요한 최소 시간을 구하는 프로그램을 작성하시오.

고슴도치는 물이 찰 예정인 칸으로 이동할 수 없다. 즉, 다음 시간에 물이 찰 예정인 칸으로 고슴도치는 이동할 수 없다. 이동할 수 있으면 고슴도치가 물에 빠지기 때문이다. 

입력:

첫째 줄에 50보다 작거나 같은 자연수 R과 C가 주어진다.

다음 R개 줄에는 티떱숲의 지도가 주어지며, 문제에서 설명한 문자만 주어진다. 'D'와 'S'는 하나씩만 주어진다.

출력:

첫째 줄에 고슴도치가 비버의 굴로 이동할 수 있는 가장 빠른 시간을 출력한다. 만약, 안전하게 비버의 굴로 이동할 수 없다면, "KAKTUS"를 출력한다.

풀이방법:

 이 문제의 핵심은 물과 고슴도치의 이동을 BFS로 확인하면서 고슴도치가 비버의 집까지 갈 때까지 물의 영향을 받지 않는 지 확인해야 한다.

 우선 물에 대해서 BFS를 수행하면서 한 번 퍼질 때마다 1씩 늘어나면서 visit 배열이 채워진다. 이 때, 벽이나 비버의 집에는 물이 차지 않도록 한다.

 그 다음에는 고슴도치의 이동에 대해서 BFS를 수행하며 배열 안에 존재하며 비버의 집을 찾을 때 종료되도록 한다. 고슴도치가 이동할 때에는 물이 퍼진 정도에 따라 이동을 할 수 있으며, 물의 visit 배열 값보다 작을 때에만 이동할 수 있다. (물의 값이 4, 고슴도치가 이동할 값이 5라면 이동 불가 -> 물이 이미 차 있기 때문)

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
def main():
    from collections import deque
 
    dx = [-1,0,1,0]
    dy = [0,1,0,-1]
 
    r,c = map(int,input().split())
    hVisit = [[0 for _ in range(c)]for _ in range(r)]
    wVisit = [[0 for _ in range(c)]for _ in range(r)]
    forest = []
    Hedgehog = deque()
    water = deque()
    for i in range(r):
        temp = input()
        forest.append([])
        for j,t in enumerate(temp):
            if t == "X":
                forest[i].append(-1)
            elif t == "S":
                forest[i].append(1)
                Hedgehog.append((i,j))
                hVisit[i][j] = 1
            elif t == "*":
                forest[i].append(2)
                water.append((i,j))
                wVisit[i][j] = 1
            elif t == '.':
                forest[i].append(0)
            elif t == 'D':
                forest[i].append(3)
 
    while len(water):
        x,y = water.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
 
            if 0<=nx<and 0<=ny<and (forest[nx][ny]!=-1 and forest[nx][ny]!=3and not wVisit[nx][ny]:
                water.append((nx,ny))
                wVisit[nx][ny] = wVisit[x][y] + 1
    while len(Hedgehog):
        x,y = Hedgehog.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if 0<=nx<and 0<=ny<and forest[nx][ny]==3:
                print(hVisit[x][y])
                return 0
            if 0<=nx<and 0<=ny<c:
                if forest[nx][ny] != -1 and not hVisit[nx][ny]:
                    if hVisit[x][y] + 1 < wVisit[nx][ny] or wVisit[nx][ny] == 0:
                        Hedgehog.append((nx,ny))
                        hVisit[nx][ny] = hVisit[x][y] +1
 
    print("KAKTUS")
    
if __name__ == "__main__":
    main()
cs

문제링크:

www.acmicpc.net/problem/3055

 

3055번: 탈출

사악한 암흑의 군주 이민혁은 드디어 마법 구슬을 손에 넣었고, 그 능력을 실험해보기 위해 근처의 티떱숲에 홍수를 일으키려고 한다. 이 숲에는 고슴도치가 한 마리 살고 있다. 고슴도치는 제

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]15686. 치킨 배달  (0) 2021.05.20
[BOJ]2583. 영역 구하기  (0) 2021.05.18
[BOJ]2630. 색종이 만들기  (0) 2021.04.29
[BOJ]3273. 두 수의 합  (0) 2021.04.27
[BOJ]9184. 신나는 함수 실행  (0) 2021.04.22

문제:

예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을 하는 게임이다. 서강그라운드에서 1등을 하면 보상으로 치킨을 주는데, 예은이는 단 한번도 치킨을 먹을 수가 없었다. 자신이 치킨을 못 먹는 이유는 실력 때문이 아니라 아이템 운이 없어서라고 생각한 예은이는 낙하산에서 떨어질 때 각 지역에 아이템 들이 몇 개 있는지 알려주는 프로그램을 개발을 하였지만 어디로 낙하해야 자신의 수색 범위 내에서 가장 많은 아이템을 얻을 수 있는지 알 수 없었다.

각 지역은 일정한 길이 l (1 ≤ l ≤ 15)의 길로 다른 지역과 연결되어 있고 이 길은 양방향 통행이 가능하다. 예은이는 낙하한 지역을 중심으로 거리가 수색 범위 m (1 ≤ m ≤ 15) 이내의 모든 지역의 아이템을 습득 가능하다고 할 때, 예은이가 얻을 수 있는 아이템의 최대 개수를 알려주자.

주어진 필드가 위의 그림과 같고, 예은이의 수색범위가 4라고 하자. ( 원 밖의 숫자는 지역 번호, 안의 숫자는 아이템 수, 선 위의 숫자는 거리를 의미한다) 예은이가 2번 지역에 떨어지게 되면 1번,2번(자기 지역), 3번, 5번 지역에 도달할 수 있다. (4번 지역의 경우 가는 거리가 3 + 5 = 8 > 4(수색범위) 이므로 4번 지역의 아이템을 얻을 수 없다.) 이렇게 되면 예은이는 23개의 아이템을 얻을 수 있고, 이는 위의 필드에서 예은이가 얻을 수 있는 아이템의 최대 개수이다.

입력:

첫째 줄에는 지역의 개수 n (1 ≤ n ≤ 100)과 예은이의 수색범위 m (1 ≤ m ≤ 15), 길의 개수 r (1 ≤ r ≤ 100)이 주어진다.

둘째 줄에는 n개의 숫자가 차례대로  각 구역에 있는 아이템의 수 t (1 ≤ t ≤ 30)를 알려준다.

세 번째 줄부터 r+2번째 줄 까지 길 양 끝에 존재하는 지역의 번호 a, b, 그리고 길의 길이 l (1 ≤ l ≤ 15)가 주어진다.

출력:

예은이가 얻을 수 있는 최대 아이템 개수를 출력한다.

풀이방법:

플로이드-와샬 알고리즘을 적용해서 이 문제를 풀 수 있다. 플로이드-와샬 알고리즘은 주어진 그래프의 경로로 가중치를 초기화한 후 i에서 j로 가는 경로에 k가 추가 되었을 때, 이전의 경로의 가중치보다 작아지는지 확인하면 된다. 

플로이드-와샬로 초기화를 완료한 뒤에, 지역의 개수 n을 반복문으로 순회한다. 순회하면서 임계점에 해당하는 값인 m보다 작은 값들을 모두 더해주고, 마지막에 현재 시작한 지역의 값을 더해주도록 한다. 이 중 가장 큰 값을 출력하도록 한다.

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
import sys
 
n,m,r = map(int,input().split())
items = list(map(int,input().split()))
MAX = float('inf')
floyd = [[MAX for _ in range(n)] for _ in range(n)]
 
for _ in range(r):
    a, b, l = map(int,input().split())
    floyd[a-1][b-1= l
    floyd[b-1][a-1= l
 
for k in range(n):
    for i in range(n):
        for j in range(n):
            floyd[i][j] = min(floyd[i][j],floyd[i][k]+floyd[k][j])
            
answer = 0
for i in range(n):
    temp = 0
    for j,v in enumerate(floyd[i]):
        if i==j:
            continue
        if v != MAX and v<=m:
            temp+=items[j]
    temp+=items[i]
    if temp >  answer:
        answer = temp
        
print(answer)
cs

문제링크:

www.acmicpc.net/problem/14938

 

14938번: 서강그라운드

예은이는 요즘 가장 인기가 있는 게임 서강그라운드를 즐기고 있다. 서강그라운드는 여러 지역중 하나의 지역에 낙하산을 타고 낙하하여, 그 지역에 떨어져 있는 아이템들을 이용해 서바이벌을

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]2661. 좋은 수열  (0) 2021.01.14
[BOJ]15711. 환상의 짝꿍  (0) 2021.01.12
[BOJ]1922. 네트워크 연결  (0) 2021.01.05
[BOJ]1613. 역사  (0) 2020.12.31
[BOJ]13908. 비밀번호  (0) 2020.12.29

문제:

도현이는 컴퓨터와 컴퓨터를 모두 연결하는 네트워크를 구축하려 한다. 하지만 아쉽게도 허브가 있지 않아 컴퓨터와 컴퓨터를 직접 연결하여야 한다. 그런데 모두가 자료를 공유하기 위해서는 모든 컴퓨터가 연결이 되어 있어야 한다. (a와 b가 연결이 되어 있다는 말은 a에서 b로의 경로가 존재한다는 것을 의미한다. a에서 b를 연결하는 선이 있고, b와 c를 연결하는 선이 있으면 a와 c는 연결이 되어 있다.)

그런데 이왕이면 컴퓨터를 연결하는 비용을 최소로 하여야 컴퓨터를 연결하는 비용 외에 다른 곳에 돈을 더 쓸 수 있을 것이다. 이제 각 컴퓨터를 연결하는데 필요한 비용이 주어졌을 때 모든 컴퓨터를 연결하는데 필요한 최소비용을 출력하라. 모든 컴퓨터를 연결할 수 없는 경우는 없다.

입력:

첫째 줄에 컴퓨터의 수 N (1 ≤ N ≤ 1000)가 주어진다.

둘째 줄에는 연결할 수 있는 선의 수 M (1 ≤ M ≤ 100,000)가 주어진다.

셋째 줄부터 M+2번째 줄까지 총 M개의 줄에 각 컴퓨터를 연결하는데 드는 비용이 주어진다. 이 비용의 정보는 세 개의 정수로 주어지는데, 만약에 a b c 가 주어져 있다고 하면 a컴퓨터와 b컴퓨터를 연결하는데 비용이 c (1 ≤ c ≤ 10,000) 만큼 든다는 것을 의미한다. a와 b는 같을 수도 있다.

출력:

모든 컴퓨터를 연결하는데 필요한 최소비용을 첫째 줄에 출력한다.

풀이방법:

 이러한 문제는 최소 스패닝 트리를 사용해서 푸는 전형적인 문제다. Kruskal, Prim 알고리즘으로 풀 수 있으며, 이번 문제는 Prim 알고리즘을 활용해서 풀었다.

 Prim 알고리즘은 다음의 순서대로 작동한다.

  1. 그래프에서 하나의 꼭짓점을 선택하여 트리를 만든다.
  2. 그래프의 모든 변이 들어 있는 집합을 만든다.
  3. 모든 꼭짓점이 트리에 포함되어 있지 않은 동안
    1. 트리의 연결된 변 가운데 트리 속의 두 꼭짓점을 연결하지 않는 가장 가중치가 작은 변을 트리에 추가한다.

 이 알고리즘이 종료되었을 때 만들어진 트리는 최소 비용 신장 트리가 된다. [출처: Prim 알고리즘 위키피디아]

 

따라서 위 알고리즘대로 해당 노드로 이동하는 최소 비용을 의미하는 distance 배열을 INF로, 전체 가중치를 가지고 있는 vertice를 초기화 하고, 모든 컴퓨터를 방문했는지 확인할 수 있는 visited 배열을 만든다.

 

 이제 1번 컴퓨터(인덱스상 0번)를 임의로 선택하여 위 알고리즘대로 트리를 만들기 시작한다. 1번 컴퓨터로 향하는 distance는 0이다. (문제 조건 상 a와 b가 같을 수 있다고 하는데 큰 의미는 없는 것 같다.) distance와 visited 배열을 바탕으로 선택해야 하는 distance를 고른다.( 첫번쨰의 경우에는 당연히 1번 컴퓨터만 distance가 변경되었으므로 1번 컴퓨터다.) 1번 컴퓨터가 선택되었으므로, 이 컴퓨터와 연결 된 Edge들을 distance에 반영한다.

 위 과정을 모든 컴퓨터를 다 방문할 때까지 반복하며, 알고리즘이 종료되었을 때의 distance의 합이 최소 비용을 의미하게 된다.

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
import sys
 
input = sys.stdin.readline
 
= int(input())
= int(input())
INF = float('inf')
 
distance = [INF]*n
vertice = [[INF for _ in range(n)] for _ in range(n)]
 
for _ in range(M):
    a,b,c = map(int,input().split())
    vertice[a-1][b-1= c
    vertice[b-1][a-1= c
 
visited = [False]*n
distance[0= 0    
while not all(visited):
    minimum = INF
    temp_node = 0
    for i in range(n):
        if not visited[i] and distance[i] < minimum:
            temp_node = i
            minimum = distance[i]
            
    visited[temp_node] = True
    for i in range(n):
        if not visited[i] and vertice[temp_node][i]!=INF:
            if (vertice[temp_node][i] < distance[i]):
                distance[i] = vertice[temp_node][i]
                
print(sum(distance))
cs

문제링크:

www.acmicpc.net/problem/1922

 

1922번: 네트워크 연결

이 경우에 1-3, 2-3, 3-4, 4-5, 4-6을 연결하면 주어진 output이 나오게 된다.

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]15711. 환상의 짝꿍  (0) 2021.01.12
[BOJ]14938. 서강그라운드  (0) 2021.01.07
[BOJ]1613. 역사  (0) 2020.12.31
[BOJ]13908. 비밀번호  (0) 2020.12.29
[BOJ]11723. 집합  (0) 2020.12.24

문제:

그래프의 정점의 집합을 둘로 분할하여, 각 집합에 속한 정점끼리는 서로 인접하지 않도록 분할할 수 있을 때, 그러한 그래프를 특별히 이분 그래프 (Bipartite Graph) 라 부른다.

그래프가 입력으로 주어졌을 때, 이 그래프가 이분 그래프인지 아닌지 판별하는 프로그램을 작성하시오.

입력:

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K(2≤K≤5)가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V(1≤V≤20,000)와 간선의 개수 E(1≤E≤200,000)가 빈 칸을 사이에 두고 순서대로 주어진다. 각 정점에는 1부터 V까지 차례로 번호가 붙어 있다. 이어서 둘째 줄부터 E개의 줄에 걸쳐 간선에 대한 정보가 주어지는데, 각 줄에 인접한 두 정점의 번호가 빈 칸을 사이에 두고 주어진다.

출력:

K개의 줄에 걸쳐 입력으로 주어진 그래프가 이분 그래프이면 YES, 아니면 NO를 순서대로 출력한다.

풀이방법:

 위키피디아에 따르면 이분 그래프란 모든 꼭짓점을 빨강과 파랑으로 색칠하되, 모든 변이 빨강과 파랑 꼭짓점을 포함하도록 색칠할 수 있는 그래프이다. 즉 한 변의 양 끝은 빨강과 파랑으로 서로 달라야 한다는 것이다.

 dfs로 정점을 탐색하며, visited에다 색을 기록한다. dfs로 탐색하는 도중에 visited에 서로 다른 색이 들어오게 되면 이분그래프가 아니므로 False를 반환하도록 한다.

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
import sys
 
sys.setrecursionlimit(10**6)
input = sys.stdin.readline
 
def dfs(cur,color):
    visited[cur] = color
    for i in vertex[cur]:
        if visited[i]==0:
            if not dfs(i,-color):
                return False
        elif visited[i] == visited[cur]:
            return False
    return True
 
= int(input())
for _ in range(K):
    V, E = map(int,input().split())
    vertex = [[] for _ in range(V+1)]
    visited = [0 for _ in range(V+1)]
    for _ in range(E):
        x, y = map(int,input().split())
        vertex[x].append(y)
        vertex[y].append(x)
        
    answer = True
    for i in range(1,V+1):
        if visited[i] == 0:
            if not dfs(i,1):
                answer=False
                break
    if answer:
        print("YES")
    else:
        print("NO")
cs

문제링크:

www.acmicpc.net/problem/1707

 

1707번: 이분 그래프

입력은 여러 개의 테스트 케이스로 구성되어 있는데, 첫째 줄에 테스트 케이스의 개수 K(2≤K≤5)가 주어진다. 각 테스트 케이스의 첫째 줄에는 그래프의 정점의 개수 V(1≤V≤20,000)와 간선의 개수

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]10835. 카드게임  (0) 2020.12.01
[BOJ]1747. 소수&팰린드롬  (0) 2020.11.26
[BOJ]7562. 나이트의 이동  (0) 2020.11.19
[BOJ]1992. 쿼드트리  (0) 2020.11.17
[BOJ]1041. 주사위  (0) 2020.11.12

문제:

체스판 위에 한 나이트가 놓여져 있다. 나이트가 한 번에 이동할 수 있는 칸은 아래 그림에 나와있다. 나이트가 이동하려고 하는 칸이 주어진다. 나이트는 몇 번 움직이면 이 칸으로 이동할 수 있을까?

입력:

입력의 첫째 줄에는 테스트 케이스의 개수가 주어진다.

각 테스트 케이스는 세 줄로 이루어져 있다. 첫째 줄에는 체스판의 한 변의 길이 l(4 ≤ l ≤ 300)이 주어진다. 체스판의 크기는 l × l이다. 체스판의 각 칸은 두 수의 쌍 {0, ..., l-1} × {0, ..., l-1}로 나타낼 수 있다. 둘째 줄과 셋째 줄에는 나이트가 현재 있는 칸, 나이트가 이동하려고 하는 칸이 주어진다.

출력:

각 테스트 케이스마다 나이트가 최소 몇 번만에 이동할 수 있는지 출력한다.

풀이방법:

너비 우선 탐색의 가장 기초적인 문제다. 이미 지나온 곳을 다시 방문하지 않도록 0으로 초기화된 visited 배열을 만들었고, 현재 stage에서 나이트가 있을 수 있는 위치를 able이라는 배열에 저장하도록 했다. 

bfs 함수 내에선 우선 able 내에 목적지가 있는지 확인하는 과정을 먼저 거친다. 있다면 현재 stage(count)를 출력하도록 하고, 없으면 나이트가 움직일 수 있는 경우의 수인 candidate를 able을 각 케이스에 대해 더해줘서 새로운 able을 만들도록 한다. 이 과정을 재귀적으로 반복하면서 값을 찾는다.

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
candidate = [(2,1),(1,2),(2,-1),(1,-2),(-1,2),(-1,-2),(-2,1),(-2,-1)]
def bfs(able,visited):
    global count
    if (eX,eY) in able:
        print(count)
    else:
        count+=1
        temp = []
        for a in able:
            for c in candidate:
                nx,ny = a[0]+c[0],a[1]+c[1]
                if 0<=nx<and 0<=ny<and visited[nx][ny]==0:
                    visited[nx][ny]=1
                    temp.append((nx,ny))
        bfs(temp,visited)
            
N=int(input())
for _ in range(N):
    l = int(input())
    sX,sY = map(int,input().split())
    eX,eY = map(int,input().split())
    visited = [[0 for _ in range(l)]for _ in range(l)]
    count=0
    able = [(sX,sY)]
    visited[sX][sY] = 1
    bfs(able,visited)
cs

문제링크:

www.acmicpc.net/problem/7562

 

7562번: 나이트의 이동

체스판 위에 한 나이트가 놓여져 있다. 나이트가 한 번에 이동할 수 있는 칸은 아래 그림에 나와있다. 나이트가 이동하려고 하는 칸이 주어진다. 나이트는 몇 번 움직이면 이 칸으로 이동할 수

www.acmicpc.net

 

'Algorithm > Python' 카테고리의 다른 글

[BOJ]1747. 소수&팰린드롬  (0) 2020.11.26
[BOJ]1707. 이분 그래프  (0) 2020.11.24
[BOJ]1992. 쿼드트리  (0) 2020.11.17
[BOJ]1041. 주사위  (0) 2020.11.12
[BOJ]1059. 수2  (0) 2020.11.10

문제:

상근이는 자신의 결혼식에 학교 동기 중 자신의 친구와 친구의 친구를 초대하기로 했다. 상근이의 동기는 모두 N명이고, 이 학생들의 학번은 모두 1부터 N까지이다. 상근이의 학번은 1이다.

 

상근이는 동기들의 친구 관계를 모두 조사한 리스트를 가지고 있다. 이 리스트를 바탕으로 결혼식에 초대할 사람의 수를 구하는 프로그램을 작성하시오.

입력:

첫째 줄에 상근이의 동기의 수 n(2<=n<=500)이 주어진다. 둘째 줄에는 리스트의 길이 m(1<=m<=10000)이 주어진다. 다음 줄부터 m개 줄에는 친구 관계 ai,bi가 주어진다. (1<=ai<bi<=n) ai와 bi가 친구라는 뜻이며, bi 와 ai도 친구관계이다.

출력:

첫째 줄에 상근이의 결혼식에 초대하는 동기의 수를 출력한다.

풀이방법:

우선 입력으로 받은 값들을 그래프 형식으로 정리를 하는 작업을 거친다. 이후 BFS 방식을 사용해서 level이 2까지 가는 친구들(친구의 친구)을 찾는다. 항상 시작은 1이므로 queue에 1을 넣고 BFS 탐색을 두번 한다. 그렇게 탐색을 마치고 1을 제거한 뒤에 배열의 길이를 출력하도록 한다.

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
n=int(input())
m=int(input())
friends=[[]for i in range(n+1)]
for i in range(m):
    a,b=map(int,input().split())
    friends[a].append(b)
    friends[b].append(a)
 
answers=[]
queue=[1]
count=1
while len(queue):
    temp=[]
    for i in queue[:]:
        for j in friends[i]:
            if j in answers or count > 2:
                continue
            else:
                answers.append(j)
                temp.append(j)
        queue.pop(0)
    queue=temp
    count+=1
answers.remove(1)
print(len(answers))
cs

 

문제링크:

https://www.acmicpc.net/problem/5567

'Algorithm > Python' 카테고리의 다른 글

[BOJ]7576. 토마토  (0) 2019.10.29
[BOJ]1049. 기타줄  (0) 2019.10.18
[BOJ]1159. 농구 경기  (1) 2019.10.16
[BOJ]1016. 제곱ㄴㄴ수  (0) 2019.10.15
[BOJ]2960. 에라토스테네스의 체  (0) 2019.10.14

문제:

 N개의 마을로 이루어진 나라가 있습니다. 이 나라의 각 마을에는 1부터 N까지의 번호가 각각 하나씩 부여되어 있습니다. 각 마을은 양방향으로 통행할 수 있는 도로로 연결되어 있는데, 서로 다른 마을간에 이동할 때는 이 도로를 지나야 합니다. 도로를 지날 때 걸리는 시간은 도로별로 다릅니다. 현재 1번 마을에 있는 음식점에서 각 마을로 음식 배달을 하려고 합니다. 각 마을로부터 음식 주문을 받으려고 하는데, N개의 마을 중에서 K 시간 이하로 배달이 가능한 마을에서만 주문을 받으려고 합니다. 다음은 N=5, K=3인 경우의 예시입니다.
 
 1번 마을에 있는 음식점은 [1,2,4,5]번 마을까지는 3이하의 시간에 배달할 수 있습니다. 그러나 3번 마을까지는 3시간 이내로 배달할 수 있는 경로가 없으므로 3번 마을에서는 주문을 받지 않습니다. 따라서 1번 마을에 있는 음식점이 배달 주문을 받을 수 있는 마을은 4개가 됩니다.
 
 마을의 개수 N, 각 마을을 연결하는 도로의 정보 road, 음식 배달이 가능한 시간 K가 매개변수로 주어질 때, 음식 주문을 받을 수 있는 마을의 개수를 return 하도록 solution 함수를 완성해주세요.
 

풀이 방법:

<Test 32 시간초과>

 DFS 방법을 사용해서 배달 거리가 K를 넘지 않을 때까지 stack 배열에 쌓으면서 계속해서 들어간다. 들어가는 과정에서 방문하는 마을은 모두 K시간 내 방문할 수 있는 곳이므로 count set에 담도록 한다.(set이므로 중복된 것을 넣어도 자동으로 사라진다.) stack 배열을 사용하는 이유는 사이클을 피하기 위해서이므로 깊은 노드를 방문하고 다시 나올 때는 stack에서 pop 하도록해서 다른 노드를 방문할 시간을 주도록 한다. 
 하지만 재귀 과정에서 문제가 발생해서 시간초과가 발생하는 것 같은데 무엇이 문제인지는 정확히 모르겠다. (정렬도 해봤지만 차이가 없었다.)
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
def delivery(stack,dist,now,roads,K):
    for r in roads[now]:
        temp=dist+r[1]
        if not r[0in stack and temp <=K:
            stack.append(r[0])
            count.add(r[0])
            delivery(stack,temp,r[0],roads,K)
            stack.pop()
    
def solution(N,road,K):
    roads=[[]for i in range(N+1)]
    for i in range(len(road)):
        if not road[i][0in roads[road[i][1]]:
            roads[road[i][1]].append((road[i][0],road[i][2]))
        if not road[i][1in roads[road[i][0]]:
            roads[road[i][0]].append((road[i][1],road[i][2]))
    stack=[1]
    dist=0
    global count
    count=set(stack)
    for r in roads[1]:
        temp=dist+r[1]
        if not r[0in stack and temp <=K:
            stack.append(r[0])
            count.add(r[0])
            delivery(stack,temp,r[0],roads,K)
            stack.pop()
    return len(count)
cs

 <2021.07.11 수정>

DFS와 같이 재귀적인 방법을 사용하는 것이 시간을 많이 소요할 것 같아 일반적으로 그래프에서 최소 거리를 구하는 방법으로 많이 사용되는 다익스트라 방법을 사용했다. 1에서 부터의 거리를 측정하기 때문에, 1에서 다익스트라로 거리를 구한 뒤에 K보다 작은 것의 갯수를 세서 반환하도록 한다.

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
import heapq
 
def dijkstra(start,dp,edge):
    dp[start] = 0
    heapq.heappush(heap,(0,start))
    
    while heap:
        weight, move = heapq.heappop(heap)
        
        if dp[move] < weight:
            continue
        for w, node in edge[move]:
            if w+weight< dp[node]:
                dp[node] = w+weight
                heapq.heappush(heap,(dp[node],node))
    return dp
 
def solution(N,road,K):
    edge = [[] for _ in range(N+1)]
    heap = []
    for i in road:
        a,b,c = i
        edge[a].append((c,b))
        edge[b].append((c,a))
    dp = [float('inf')]*(N+1)
    
    dp = dijkstra(1,dp,edge)
    answer = 0
    for i in range(1,V+1):
        if dp[i] <= K:
            answer +=1
    return answer
cs

문제 링크:

https://programmers.co.kr/learn/courses/30/lessons/12978

'Algorithm > Python' 카테고리의 다른 글

[BOJ]15649. N과M(1),(2)  (0) 2019.08.02
[BOJ]1009. 분산처리  (0) 2019.08.01
[Programmers]Lv 3. 순위  (0) 2019.07.30
[Programmers]Lv3. 가장 먼 노드  (0) 2019.07.29
[Programmers]Lv 4. 3xn 타일링  (2) 2019.07.28

문제:

 n개의 노드가 있는 그래프가 있습니다. 각 노드는 1부터 n까지 번호가 적혀있습니다. 1번 노드에서 가장 멀리 떨어진 노드의 갯수를 구하려고 합니다. 가장 멀리 떨어진 노드란 최단경로로 이동했을 때 간선의 개수가 가장 많은 노드들을 의미합니다. 

 노드의 개수 n, 간선의 대한 정보가 담신 2차우너 배열 vertex가 매개변수로 주어질 때, 1번 노드로부터 가장 멀리 떨어진 노드가 몇 개인지를 return 하도록 solution 함수를 작성해주세요.

풀이 방법:

 노드들의 최소경로 값을 나타내는 answer를 만든 뒤에 BFS 방식으로 노드들을 검사한다. 노드를 방문할 때마다 해당 node의 answer 값이 0이면 count로 초기화 해주고, count는 한 층을 더 들어갈 때 마다 1씩 증가하도록 했다. 이렇게 모든 answer가 0이 아닌 값으로 변하면(all) answer의 max값을 찾아서 max로 count를 해 답을 얻을 수 있다. 

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 solution(n, edge):
    answer = [0]*(n+1)
    newedge=[[] for i in range(len(edge)+1)]
    for i in range(len(edge)):
        if not edge[i][1in newedge[edge[i][0]]:
            newedge[edge[i][0]].append(edge[i][1])
            newedge[edge[i][0]].sort()
        if not edge[i][0in newedge[edge[i][1]]:
            newedge[edge[i][1]].append(edge[i][0])
            newedge[edge[i][1]].sort()
    answer[0],answer[1]= -1,-1
    queue=[1]
    count=1
    while not all(answer):
        temp=[]
        for start in queue:
            for i in newedge[start]:
                if answer[i] ==0:
                    answer[i]+=count
                    temp.append(i)
        queue=temp
        count+=1
    ans=answer.count(max(answer))
    return ans
cs

문제 링크:


'Algorithm > Python' 카테고리의 다른 글

[Programmers]Lv 3.배달  (3) 2019.07.31
[Programmers]Lv 3. 순위  (0) 2019.07.30
[Programmers]Lv 4. 3xn 타일링  (2) 2019.07.28
[BOJ]2805. 나무 자르기  (0) 2019.07.27
[BOJ]1654.랜선 자르기  (0) 2019.07.26

+ Recent posts