[백준] 4485번: 녹색 옷 입은 애가 젤다지? (C++)

2024. 3. 6. 21:00·Algorithm/문제 풀이

문제


문제링크: https://www.noj.am/4485

 

4485번: 녹색 옷 입은 애가 젤다지?

젤다의 전설 게임에서 화폐의 단위는 루피(rupee)다. 그런데 간혹 '도둑루피'라 불리는 검정색 루피도 존재하는데, 이걸 획득하면 오히려 소지한 루피가 감소하게 된다! 젤다의 전설 시리즈의 주

www.acmicpc.net

 

문제 분석


동굴 내부에 도둑 루피들만이 쫙 깔려있는 상황이다.

 

어차피 잃을 수밖에 없지만

기왕 이렇게 된 거, 최대한 덜 잃게 가보자는 것이다.

 

 

자세한 풀이


DP로 풀어야겠다고 생각해서

오케이, 최소로 만들면서 내려가보자고~

 

위쪽, 왼쪽 중 최소인 것만을 선택해 합해주는 로직을 만들었따

 

#include <bits/stdc++.h>
using namespace std;

int N;
int cnt=1;
int board[126][126];
int dp[126][126];

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    
    while(1){
    	cin >> N;
    	if(!N)break;
    	
    	for(int i=1;i<=N;i++)
    		for(int j=1;j<=N;j++)
    			cin >> board[i][j];
    			
    	for(int i=1;i<=N;i++)
    		for(int j=1;j<=N;j++){
    			if(i==1)dp[i][j]=dp[i][j-1]+board[i][j];
    			else if(j==1)dp[i][j]=dp[i-1][j]+board[i][j];
    			else dp[i][j]=min(dp[i-1][j],dp[i][j-1])+board[i][j];
    		}
    	
    	cout << "Problem " << cnt++ << ": " << dp[N][N] << '\n';
	}
}

 

그리고 가볍게 제출~

하기 전에 테스트 케이스를 돌려보았는데,

 

 

?

2번 문제 왜 20으로 나와

 

음, 근데 20 맞지 않나 ?

~~라고 생각했었다

 

그래서 직접 수동 DP를 해봤는데,

// 수동 DP

case 1, 충족
 5 10 14
 8 17 15
11 13 20

case 2, 반례
 3 10 12 12 13
 5 13 12 21 14
 6  8  9 17 15
15 16 18 19 15
18 22 23 20 20

위는 DP로 풀었을 경우, 답 20

 

1번은 문제 없었고,

2번은 직접 해봐도 20이 나오는 거시어따

 

잘못 더했나 싶어서 2번 더 해봤는데 똑같이 20이었다.

 

.

.

Hoxy..

 

내가 아예 잘못 생각하고 있나?

 

이쯤되면 킹리적 갓심으로 능지 이슈가 의심된다.

어케 19가 나오는지, 내가 젤다가 되어보자

 

 

DP로 풀 수 없는 이유


 3 11 11 12
 5  9 13
 6  8  9 14
         14
         19
하지만 위 경우처럼 위로 돌아갈 경우,
답은 19로 더 효율적인 코스가 존재하게 됨.

아

ㅏ

 

선택지가 오른쪽, 아래만 있는 게 아니라서

이걸로는 모든 경우를 고려할 수가 없었던 것이다.

 

DAG가 아니라는 건데,

쉽게 말하면 순환고리가 있어서

지나온 길을 다시 돌아갈 수 있다는 의미
(왔던 길 말고, 뒤로 돌아간다고)

 

DAG란? 재윤심의 블로그 참고

 

재귀의 요정은 잠시 들어가있어

 

이제 BFS 탐색으로 풀어볼까

 

이차원 배열을 모두 최대값으로 채워놓고,

일반적으로 써왔던 BFS 로직을 적용해주면?

#include <bits/stdc++.h>
#define X first
#define Y second
using namespace std;

int N;
int cnt=1;
int board[126][126];
int zelda[126][126];

int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
queue<pair<int,int>> Q;

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    
    while(1){
    	cin >> N;
    	if(!N)break;
    	
    	for(int i=0;i<N;i++)
    		for(int j=0;j<N;j++)
    			cin >> board[i][j];
    			
    	fill_n(zelda[0],126*126,200000);
    	
    	Q.push({0,0});
    	zelda[0][0]=board[0][0];
    	
    	while(!Q.empty()){
    		auto cur=Q.front(); Q.pop();
    		for(int i=0;i<4;i++){    			
				int nx=cur.X+dx[i];
				int ny=cur.Y+dy[i];
				
				if(nx<0||nx>=N||ny<0||ny>=N)continue;
				if(zelda[nx][ny]<zelda[cur.X][cur.Y]+board[nx][ny])continue;
				Q.push({nx,ny});
				zelda[nx][ny]=zelda[cur.X][cur.Y]+board[nx][ny];
			}
		}
    	
    	cout << "Problem " << cnt++ << ": " << zelda[N-1][N-1] << '\n';
	}
}

이런 코드가 나오게 된다.

 

그럼 이제 가볍게 제출~

 

또 다른 위협


?

 

왜

또 뭐가 문제야 대체

 

코드를 이곳 저곳 만져보다가

내가 BFS 로직 내부에서 예외처리하던 부분을 continue로 빼는 게 아니라

&&로 묶어서 만족할 때만 진행하도록 바꾸니 만족했다.

 

예외 하나하나 continue보다

맞는 조건일 때만 진행하는 게 더 효율적이라는 교훈을 얻었다

 

하긴, 그렇긴해~

앞으로는 이 방식으로 fix

 

#include <bits/stdc++.h>
#define X first
#define Y second
using namespace std;

int N;
int cnt=1;
int board[126][126];
int zelda[126][126];

int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
queue<pair<int,int>> Q;

int main(){
    ios_base::sync_with_stdio(0); cin.tie(0);
    
    while(1){
    	cin >> N;
    	if(!N)break;
    	
    	for(int i=0;i<N;i++)
    		for(int j=0;j<N;j++)
    			cin >> board[i][j];
    			
    	fill_n(zelda[0],126*126,200000);
    	
    	Q.push({0,0});
    	zelda[0][0]=board[0][0];
    	
    	while(!Q.empty()){
    		auto cur=Q.front(); Q.pop();
    		for(int i=0;i<4;i++){    			
				int nx=cur.X+dx[i];
				int ny=cur.Y+dy[i];
				
				if(nx>=0&&nx<N&&ny>=0&&ny<N)
					if(zelda[nx][ny]>zelda[cur.X][cur.Y]+board[nx][ny]){
						Q.push({nx,ny});
						zelda[nx][ny]=zelda[cur.X][cur.Y]+board[nx][ny];
					}
			}
		}
    	
    	cout << "Problem " << cnt++ << ": " << zelda[N-1][N-1] << '\n';
	}
}

 

궁금한 점은 댓글로~

'Algorithm > 문제 풀이' 카테고리의 다른 글

[프로그래머스] Lv.1 택배 상자 꺼내기 (Java)  (0) 2025.03.06
[백준] 25945: 컨테이너 재배치 (C / C++)  (1) 2023.10.08
[백준] 1063번: 킹 (C++)  (0) 2023.09.24
[백준] 2630번: 색종이 만들기 (C++)  (0) 2023.08.16
[백준] 12789번: 도키도키 간식드리미 (C++)  (0) 2023.08.14
'Algorithm/문제 풀이' 카테고리의 다른 글
  • [프로그래머스] Lv.1 택배 상자 꺼내기 (Java)
  • [백준] 25945: 컨테이너 재배치 (C / C++)
  • [백준] 1063번: 킹 (C++)
  • [백준] 2630번: 색종이 만들기 (C++)
잭희
잭희
  • 잭희
    int main(){
    잭희
  • 전체
    오늘
    어제
    • 분류 전체보기 (34)
      • C 연구 노트 (3)
      • Rust 연구 노트 (8)
        • Rust 이야기 (4)
        • "EzyTutors" 프로젝트 (4)
      • Computer Science (0)
      • Back-end (2)
      • Algorithm (9)
        • 이론 (2)
        • 문제 풀이 (7)
      • Etc. (9)
      • 소소한 이야기 (3)
      • 일상 (0)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.3
잭희
[백준] 4485번: 녹색 옷 입은 애가 젤다지? (C++)
상단으로

티스토리툴바