[BAEKJOON] 1937번 욕심쟁이 판다

2024. 4. 7. 20:07·Algorithm/Dynamic Programming

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

 

1937번: 욕심쟁이 판다

n × n의 크기의 대나무 숲이 있다. 욕심쟁이 판다는 어떤 지역에서 대나무를 먹기 시작한다. 그리고 그 곳의 대나무를 다 먹어 치우면 상, 하, 좌, 우 중 한 곳으로 이동을 한다. 그리고 또 그곳에

www.acmicpc.net

문제조건
  1. n x n 크기의 대나무숲
  2. 어디든지 판다를 풀어놓을수 있다.
  3. 판다는 대나무를 다먹으면 상, 하, 좌, 우 중 한지역으로 이동한다.
  4. 이동하는 칸의 대나무가 원래있던 칸의 대나무 수보다 많아야 이동한다.
  5. 가장 많이 이동하는 경우의 이동수는?
접근방법

 

문제를 보자마자 생각이 들었다.

'아 그냥 완전탐색돌려서 최댓값 갱신해서 찾자'

내가 좋아하는 DFS 알고리즘으로 모든 경우의 수를 계산했다.

 

#include <iostream>
#include <vector>

using namespace std;

int n, map[501][501], visited[501][501];
int dy[] = { -1, 0, 1, 0 };
int dx[] = { 0, -1, 0, 1 };
int sum, res;

void dfs(int y, int x, int cnt) {
	sum = max(sum, cnt);
	for (int i = 0; i < 4; i++) {
		int ny = y + dy[i];
		int nx = x + dx[i];
		if (ny >= n || ny < 0 || nx >= n || nx < 0) continue;
		if (map[y][x] < map[ny][nx] && !visited[ny][nx]) {
			visited[ny][nx] = 1;
			dfs(ny, nx, cnt + 1);
			visited[ny][nx] = 0;
		}
	}
}

//판다 많이 이동시키기
int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) cin >> map[i][j];
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			visited[i][j] = 1;
			dfs(i, j, 1);
			visited[i][j] = 0;
			res = max(res, sum);
		}
	}
	cout << res;
}

뭐야 너무 쉬운데,,?

 

라고 생각이들면 항상 틀리는 증후군이 있는것 같다 ㅎㅎㅎ

 

위 코드를 살펴보면 500 x 500 인 이중 for문을 돌고 있고, 이중 for문을 도는 것만해도 25만이라는 시간이 걸린다.

그런데 여기서 각 반복때마다 DFS를 수행하면 최악의 경우, 억단위가 넘어가버린다,,,

이제 해결을 하기 위해서 어떻게 하면 시간을 줄일 수 있을까 생각해봤다.


내가 짠 코드는 모든 경우의 수를 고려 한 것뿐만 아니라, 중복되는 경우의 수까지 계산하고 있다.

따라서 시간이 초과가 된 것인데, 이렇게 되면 DP를 활용한 memoization기법을 통해 이미 계산된 값들은 계산하는 과정없이 스킵하는 것이 필요하다.

 

 

memoization

 

동적계획법에서 이 방식은 top-bottom Approach를 적용한 하향식 접근방법이다.

필요한 값이 있으면, 앞에서 미리 계산해두었던 값들을 활용해서 구할 수 있기 때문에, 시간적으로 매우 이득을 볼 수 있는 장점을 가진다.

이 문제에 적용해보면, 4개의 방향으로 간 DFS로 계산한것에서 +1 한거랑  판다가 있는 좌표에서 이동하는 수랑 비교해서 큰값으로 갱신 시켜주면 된다!

소스코드
#include <iostream>
#include <vector>

using namespace std;

int n, map[501][501], dp[501][501];
int dy[] = { -1, 0, 1, 0 };
int dx[] = { 0, -1, 0, 1 };
int res;

int dfs(int y, int x) {
	if (dp[y][x]) return dp[y][x];
	dp[y][x] = 1;
	for (int i = 0; i < 4; i++) {
		int ny = y + dy[i];
		int nx = x + dx[i];
		if (ny >= n || ny < 0 || nx >= n || nx < 0) continue;
		if (map[y][x] < map[ny][nx]) {
			dp[y][x] = max(dp[y][x], dfs(ny, nx) + 1);
		}
	}
	return dp[y][x];
}

//판다 많이 이동시키기
int main() {
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++) cin >> map[i][j];
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			res = max(res, dfs(i, j));			
		}
	}
	cout << res;
}

 

'Algorithm > Dynamic Programming' 카테고리의 다른 글

[BAEKJOON] 1162번 도로포장  (1) 2024.05.23
[BAEKJOON] 1446번 지름길  (0) 2024.05.13
[BAEKJOON] 14501번 퇴사  (1) 2024.04.07
[BAEKJOON] 3114번 사과와 바나나  (0) 2024.04.05
[BAEKJOON] 9252번 LCS 2  (0) 2024.03.29
'Algorithm/Dynamic Programming' 카테고리의 다른 글
  • [BAEKJOON] 1162번 도로포장
  • [BAEKJOON] 1446번 지름길
  • [BAEKJOON] 14501번 퇴사
  • [BAEKJOON] 3114번 사과와 바나나
Ls._.Rain
Ls._.Rain
안되면 될때까지 삽질했던 기록
  • Ls._.Rain
    Ls{Diary}
    Ls._.Rain
  • 전체
    오늘
    어제
    • 분류 전체보기 (136)
      • Github (2)
      • Spring (51)
        • Batch Programming (13)
        • 결제 (4)
        • 대용량 트래픽 (32)
        • OpenAI (0)
        • Security (0)
        • WebSocket (0)
        • JPA (1)
      • Algorithm (67)
        • DFS (6)
        • BFS (6)
        • Dynamic Programming (10)
        • Brute Force (4)
        • Binary Search (6)
        • 구현, 시뮬레이션 (15)
        • Stack (1)
        • Greedy (4)
        • Priority_Queue (2)
        • Back Tracking (3)
        • Geometry (2)
        • SCC (1)
        • 투포인터 (4)
        • 최대유량 (1)
        • 정렬 (1)
      • OS (0)
      • DevOps (15)
        • AWS (11)
        • Docker (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • hELLO· Designed By정상우.v4.10.0
Ls._.Rain
[BAEKJOON] 1937번 욕심쟁이 판다
상단으로

티스토리툴바