문제:

n*n의 크기의 대나무 숲이 있다. 욕심쟁이 판다는 어떤 지역에서 대나무를 먹기 시작한다. 그리고 그 곳의 대나무를 다 먹어 치우면 상, 하, 좌, 우 중 한 곳으로 이동을 한다. 그리고 또 그곳에서 대나무를 먹는다. 그런데 단 조건이 있다. 이 판다는 매우 욕심이 많아서 대나무를 먹고 자리를 옮기면 그 옮긴 지역에 그 전 지역보다 대나무가 많이 있어야 한다. 만약에 그런 지점이 없으면 이 판다는 불만을 가지고 단식 투쟁을 하다가 죽게 된다.(-_-)

이 판다의 사육사는 이런 판다를 대나무 숲에 풀어 놓아야 하는데, 어떤 지점에 처음에 풀어 놓아야 하고, 어떤 곳으로 이동을 시켜야 둘 다 소중한 생명이지만 판다가 최대한 오래 살 수 있는지 고민에 빠져 잇따. 우리의 임무는 이 사육사를 도와주는 것이다. n*n 크기의 대나무 숲이 주어져 있을 때, 이 판다가 최대한 오래 살려면 어떤 경로를 통하여 움직여야 하는지 구하여라.

입력:

첫째 줄에 대나무 숲의 크기 n(1<=n<=500)이 주어진다. 그리고 둘째 줄부터 n+1번째 줄까지 대나무 숲의 정보가 주어진다. 대나무 숲의 정보는 공백을 사이로 두고 각 지역의 대나무의 양이 정수 값으로 주어진다. 대나무의 양은 1,000,000보다 작거나 같은 자연수이다.

출력:

첫째 줄에는 판다가 최대한 살 수 있는 일수(K)를 출력한다.

풀이방법:

 기본적으로는 dfs를 사용해서 판다의 이동 경로를 알아야 하지만 문제에서 원하는 것은 판다가 최대한 살 수 있는 일수, 즉 최대로 이동 가능한 거리의 길이를 원하고 있다. 작은 크기의 경우에는 시작점을 달리 해서 최대 일수를 찾을 수 있지만 500 x 500의 경우에는 이 것을 다 탐색하기에는 많은 시간이 걸릴 것이다.

 따라서 이를 해결하기 위해서 다이나믹 프로그래밍에서 메모리제이션을 사용한다. 한 점에서 출발을 해서 움직이다가 이미 이전에 다른 곳에서 움직였던 기록이 남아있고 그것을 기록해뒀다면 더 이상 그 길로 이동할 필요없이 그 값을 참조해서 다시 돌아오면 된다. 따라서 dfs로 이동을 하지만 이전에 이 길을 지나간 기록이 있다면 그 값을 가져오고, 그렇지 않다면 더 들어가면서 값을 기록하도록 한다.

 또한 재귀적으로 함수를 구현했기 때문에 깊은 재귀로 인한 에러를 방지하기 위해서 sys.setrecursionlimit를 사용한다.

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
sys.setrecursionlimit(1000000)
 
def dfs(x,y):
    global answer
    
    if dp[x][y] != 0:
        return dp[x][y]
 
    dp[x][y] = 1
    for i in range(4):
        nx = x+dx[i]
        ny = y+dy[i]
        if 0 <= nx< n and 0 <= ny< n:
            if trees[nx][ny] > trees[x][y]:
                dp[x][y] = max(dp[x][y], dfs(nx, ny)+1)
    return dp[x][y]
 
dx = [001-1]
dy = [1-100]
= int(input())
trees = []
for _ in range(n):
    trees.append(list(map(int, input().split())))
 
answer = 0
visited = [[0 for _ in range(n) ] for _ in range(n)]
dp = [[0 for _ in range(n) ] for _ in range(n)]
 
for i in range(n):
    for j in range(n):
        answer = max(dfs(i,j),answer)
print(answer)
cs

문제링크:

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

 

1937번: 욕심쟁이 판다

n*n의 크기의 대나무 숲이 있다. 욕심쟁이 판다는 어떤 지역에서 대나무를 먹기 시작한다. 그리고 그 곳의 대나무를 다 먹어 치우면 상, 하, 좌, 우 중 한 곳으로 이동을 한다. 그리고 또 그곳에서 대나무를 먹는다. 그런데 단 조건이 있다. 이 판다는 매우 욕심이 많아서 대나무를 먹고 자리를 옮기면 그 옮긴 지역에 그 전 지역보다 대나무가 많이 있어야 한다. 만약에 그런 지점이 없으면 이 판다는 불만을 가지고 단식 투쟁을 하다가 죽게 된다(-_-) 이

www.acmicpc.net

 

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

[BOJ]2358. 평행선  (0) 2019.11.13
[BOJ]GIT- 정리  (0) 2019.11.12
[BOJ]6359. 만취한 상범  (0) 2019.11.09
[BOJ]1965. 상자넣기  (0) 2019.11.08
[BOJ]2225. 합분해  (0) 2019.11.07

문제:

서강대학교 곤자가 기숙사의 지하에는 n개의 방이 일렬로 늘어선 감옥이 있다. 각 방에는 벌점을 많이 받는 학생이 구금되어있다.

그러던 어느 날, 감옥 간수인 상범이는 지루한 나머지 정신나간 게임을 하기로 결정했다. 게임의 첫 번째 라운드에서 상범이는 위스키를 한 잔 들이키고, 달려가며 감옥을 한 개씩 모두 연다. 그 다음 라운드에서는 2,4,6, ... 번 방을 다시 잠그고, 세 번째 라운드에서는 3, 6, 9, ... 번 방이 열려있으면 잠그고, 잠겨있으면 연다. k번째 라운드에서는 번호가 k인 배수인 방이 열려 있으면 잠그고, 잠겨 있으면 연다. 이렇게 n번째 라운드까지 진행한 이후, 상범이는 위스키의 마지막 병을 마시고 쓰러져 잠든다.

입력:

입력의 첫 번째 줄에는 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄에 한 개씩 방의 개수 n(5<=n<=100)이 주어진다.

출력:

한 줄에 한 개씩 각 테스트 케이스의 답, 즉 몇 명이 탈출할 수 있는지를 출력한다.

 

풀이방법:

다이나믹 프로그래밍으로 풀어야 한다고 하는데 방의 개수가 100으로 작은편이기 때문에 완전탐색을 사용해서 풀었다.

0이면 열려 있고, 1이면 닫혀 있다고 했을 때, 해당하는 숫자 j의 배수마다 0이면 1로, 1이면 0으로 바꾸도록 했다. 이렇게 모두 탐색을 완료하면 0의 갯수에서 하나를 빼서 답을 구한다.

(다 풀고나니 1을 열려 있고, 0을 닫혀 있다 가정하고, 마지막에 sum을 하는 것이 더 깔끔할 것 같다.)

1
2
3
4
5
6
7
8
9
10
11
T=int(input())
for i in range(T):
    n=int(input())
    answer=[0]*(n+1)
    for j in range(2,n+1):
        for k in range(j,n+1,j):
            if answer[k]==0:
                answer[k]=1
            else:
                answer[k]=0
    print(answer.count(0)-1)
cs

문제링크:

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

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

[BOJ]GIT- 정리  (0) 2019.11.12
[BOJ]1937. 욕심쟁이 판다  (0) 2019.11.11
[BOJ]1965. 상자넣기  (0) 2019.11.08
[BOJ]2225. 합분해  (0) 2019.11.07
[BOJ]1010. 다리 놓기  (0) 2019.11.06

+ Recent posts