반응형
❔ 문제 요약
https://www.acmicpc.net/problem/15558
- 총 2줄의 N칸짜리 보드가 주어진다.
- 유저는 왼쪽 줄의 1번 칸에서 시작한다.
- 매 초마다 3가지 중 하나의 이동을 할 수 있다
- 앞으로 1칸 이동
- 뒤로 1칸 이동
- 반대편 줄의 (현재 칸 + k)칸으로 점프
- 칸은 시간이 지나면서 사라진다 -> t초가 지나면 1~t번 칸은 사라져서 이동 불가
- N을 넘어가면 게임 클리어
🔑 해결 전략: BFS
- 단순한 BFS처럼 보이지만, 시간 경과에 따라 칸이 사라지는 조건이 핵심
- 각 칸에 도착할 때의 시간을 저장해두고,
- 그 칸이 아직 살아있는지(시간 < 칸 번호) 확인해야 함
- 이미 더 빠르게 도달한 적 있다면 재방문하지 않음
💙 Step 1: 보드 설정
int B[2][MAX]; // 2줄의 보드, 1이면 안전, 0이면 위험
for (int i = 0; i < 2; i++) {
string str; cin >> str;
for (int j = 0; j < str.size(); j++) {
if (str[j] == '1') B[i][j+1] = INT_MAX; // 안전한 칸
else B[i][j+1] = 0; // 위험한 칸
}
}
안전한 칸은 1 대신 INT_MAX를 넣고, 나중에 최소 시간으로 갱신해 나감
💙 Step 2: BFS 탐색
B[0][1] = 1; // 시작점 시간 = 1
queue<pair<int,int>> q;
q.push({1,0}); // (위치 1, 줄 0)
각 위치에서 3가지 행동에 대하여 탐색
➡️ 앞으로 한 칸
if (B[line][pos+1] && B[line][pos+1] > B[line][pos] + 1) {
B[line][pos+1] = B[line][pos] + 1;
q.push({pos+1, line});
}
이동할 수 있는 칸(안전한 칸)이고, 이전보다 더 빠른 시간으로 도달하면 갱신
⬅️ 뒤로 한 칸
if(pos-1>=1 && B[line][pos-1]){
if(B[line][pos-1]>B[line][pos]+1 && B[line][pos]+1<=pos-1){
B[line][pos-1] = B[line][pos]+1;
q.push({pos-1,line});
}
}
- pos-1>=1 : 뒤로 갔을때 1보다 같거나 큰 경우만 이동 (OutOfIndex 방지)
- B[line][pos-1] : 안전한 칸인 경우만 이동
- B[line][pos-1]>B[line][pos]+1 : 갱신이 가능하고
- B[line][pos]+1<=pos-1 : 아직 칸이 없어지지 않아서 밟을 수 있을때만 큐에 추가
🔁 반대편 줄로 점프
if(B[(line+1)%2][pos+k]){ // 안전한 칸이고
if(B[(line+1)%2][pos+k]>B[line][pos]+1){ // 갱신이 가능하다면
B[(line+1)%2][pos+k]=B[line][pos]+1;
q.push({pos+k,(line+1)%2});
}
}
✅ isClear 함수
void isClear(int pos){
if(pos > n){
cout << 1 << '\n';
exit(0);
}
}
현재 위치가 n 초과면 즉시 게임 클리어 → exit(0)으로 종료
✅ 정답 코드
// 15558 점프게임
// 메모리제이션 + 큐
#include<iostream>
#include<queue>
#include<climits>
#include<algorithm>
#include<string>
#define MAX 100'001
using namespace std;
int B[2][MAX];
int n;
void isClear(int pos){
if(pos>n){
cout<<1<<'\n';
exit(0);
};
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int k; cin>>n>>k; // 1 ≤ N, k ≤ 100,000
for(int i=0,tmp;i<2;i++){
string str; cin>>str;
for(int j=0;j<str.size();j++){
if(str[j]=='1')B[i][j+1]=INT_MAX; // 갈 수 있는 곳이라면 최대값으로 초기화 -> 이후 최솟값으로 갱신해 나갈것
else B[i][j+1]=0;
}
}
B[0][1]=1; // 왼쪽 줄의 1번 칸은 항상 안전한 칸
queue<pair<int,int>> q; // 현재 위치, 현재 줄
q.push({1,0}); // 0번째줄 1번에서 시작
while(!q.empty()){
int pos=q.front().first;
int line=q.front().second;
q.pop();
// 앞으로 한칸
isClear(pos+1);
if(B[line][pos+1]){ // 0이 아닐떄(위험한 칸이 아닐 때) 수행
if(B[line][pos+1]>B[line][pos]+1){
B[line][pos+1] =B[line][pos]+1;
q.push({pos+1,line});
}
}
// 뒤로 한칸
if(pos-1>=1 && B[line][pos-1]){
if(B[line][pos-1]>B[line][pos]+1 && B[line][pos]+1<=pos-1){
B[line][pos-1] = B[line][pos]+1;
q.push({pos-1,line});
}
}
// 건너편으로
isClear(pos+k);
if(B[(line+1)%2][pos+k]){
if(B[(line+1)%2][pos+k]>B[line][pos]+1){
B[(line+1)%2][pos+k]=B[line][pos]+1;
q.push({pos+k,(line+1)%2});
}
}
}
cout<<0<<'\n';
}
💥 시행착오 : 메모리 초과 발생 원인과 해결
// 15558 점프게임
// 메모리제이션 + 큐
#include<iostream>
#include<queue>
#include<climits>
#include<algorithm>
#include<string>
#define MAX 100'001
using namespace std;
int B[2][MAX];
int n;
void isClear(int pos){
if(pos>n){
cout<<1<<'\n';
exit(0);
};
}
int main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
// freopen("input.txt","r",stdin);
int k; cin>>n>>k; // 1 ≤ N, k ≤ 100,000
for(int i=0,tmp;i<2;i++){
string str; cin>>str;
for(int j=0;j<str.size();j++){
if(str[j]=='1')B[i][j+1]=INT_MAX; // 갈 수 있는 곳이라면 최대값으로 초기화 -> 이후 최솟값으로 갱신해 나갈것
else B[i][j+1]=0;
}
}
B[0][1]=1; // 왼쪽 줄의 1번 칸은 항상 안전한 칸
queue<pair<int,int>> q; // 현재 위치, 현재 줄
q.push({1,0}); // 0번째줄 1번에서 시작
while(!q.empty()){
int pos=q.front().first;
int line=q.front().second;
q.pop();
// 앞으로 한칸
isClear(pos+1);
if(B[line][pos+1]){ // 0이 아닐떄(위험한 칸이 아닐 때) 수행
B[line][pos+1] = min(B[line][pos+1],B[line][pos]+1);
q.push({pos+1,line});
}
// 뒤로 한칸
if(pos-1>=1 && B[line][pos-1]){
B[line][pos-1] = min(B[line][pos-1],B[line][pos]+1);
// 아직 칸이 없어지지 않아서 밟을 수 있다면 큐에 추가
if(B[line][pos]+1<=pos-1) q.push({pos-1,line});
}
// 건너편으로
isClear(pos+k);
if(B[(line+1)%2][pos+k]){
B[(line+1)%2][pos+k] = min(B[(line+1)%2][pos+k],B[line][pos]+1);
q.push({pos+k,(line+1)%2});
}
}
cout<<0<<'\n';
}
- 원인 : min()만 써서 무조건 큐에 추가
이렇게 하게 되면 이미 방문한 칸도 다시 큐에 넣는 상황이 발생
min()으로만 갱신하면서 더 느린 시간이어도 무조건 q.push()를 하게 되고,
동일한 칸을 여러 번 방문 → 큐의 크기가 비정상적으로 커짐 → 메모리 초과
- 해결 : 조건 추가로 큐 삽입 제한
도달 시간이 더 빠를 때만 큐에 추가하도록 수정
반응형
'백준' 카테고리의 다른 글
[c++] 백준 1707 이분 그래프 (0) | 2025.06.08 |
---|---|
[c++] 백준 21940 가운데에서만나기 (0) | 2025.06.08 |
[c++] 6603 로또 - 조합 (0) | 2025.06.06 |
[c++] 2108 통계학 (1) | 2025.06.06 |
[c++] 백준 14888 연산자 끼워넣기 (0) | 2025.05.06 |