반응형

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

 

20061번: 모노미노도미노 2

모노미노도미노는 아래와 같이 생긴 보드에서 진행되는 게임이다. 보드는 빨간색 보드, 파란색 보드, 초록색 보드가 그림과 같이 붙어있는 형태이다. 게임에서 사용하는 좌표 (x, y)에서 x는 행,

www.acmicpc.net

1. 문제설명

구조 설계를 꼼꼼히 잘 해야 해결할 수 있는 문제이다.

먼저 파란색 블록과 초록색 블록 영역은 동일하게 둘 수 있다.

들어오는 블록이 1x2거나 2x1일 때 그 블록을 서로 바꿔서 파란 영역과 초록 영역에 넣어주면 동일한 구조를 지닌다.

 

즉 input 블록만 회전시켜주면 초록색 영역과 파란색 영역에 동일한 시행을 하면 된다.

이를 바탕으로

나는 함수를 세가지를 만들었는데

 

1. 블록을 쌓는 함수,

2. 현재 쌓인 블록에서 지워질 라인이 있는지 확인하고 지우며 점수를 증가시키는 함수

3. 특별한 영역에 블록이 있는지 확인하고 그에 따라 전체 블록을 옮기는 함수.

 

이 세 함수를 들어오는 블록마다 파란영역과 초록 영역에 시행하면

문제를 해결할 수 있다.

 

주의해야할 점은

2. 현재 쌓인 블록에서 지워질 라인이 있는지 확인하고 지운 후

다시 현재 라인부터 검사해야한다.

왜냐하면 현재 라인은 이후에 검사할 라인에서 당겨왔기 때문에

검사가 안된 상태이기 때문이다.

 

 

이러한 삼성기출문제의 구현, 시뮬레이션 문제는 

생각을 구조화하고 짜임새있게 해주어서 좋은 문제인 것 같다.

 

 

2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;

int N, point;
bool blueBoard[4][6], greenBoard[4][6];


void buildBlock(int t, int x, int y, bool board[][6]) {
    if(t==1){
        int ny = 0;
        while(ny+1 <= 5 && board[x][ny+1] ==0 ){
            ny++;
        }
        board[x][ny] = 1;
    }
    else if(t==2){
        int ny = 0;
        while(ny+1 <= 5 && board[x][ny+1] ==0 ){
            ny++;
        }
        board[x][ny] = 1;
        board[x][ny-1] = 1;

    }
    else if(t==3){
        int nyFirst = 0;
        while(nyFirst+1 <= 5 && board[x][nyFirst+1] ==0 ){
            nyFirst++;
        }

        int nySecond = 0;
        while(nySecond+1 <= 5 && board[x+1][nySecond+1] ==0 ){
            nySecond++;
        }

        int ny = min(nyFirst, nySecond);

        board[x][ny] = 1;
        board[x+1][ny] = 1;
    }
}

void checkNormalLine(bool blueBoard[][6]) {
    for(int i=5; i>=2; i--){
        bool flag = true;

        for(int j=0; j<4; j++){
            if(!blueBoard[j][i]){
                flag = false;
                break;
            }
        }

        if(flag){
            //Line delete;
            point++;
            for(int j=i; j>=1; j--){
                for(int k=0; k<4; k++){
                    blueBoard[k][j] = blueBoard[k][j-1];
                }
            }

            for(int k=0; k<4; k++){
                blueBoard[k][0] = 0;
            }
            //cur Line recheck!
            i++;
        }
    }
}

void checkSpecialLine(bool blueBoard[][6]) {
    bool flag0 = false;
    bool flag1 = false;
    for(int i=0; i<4; i++){
        if(blueBoard[i][0]){
            flag0 = true;
        }
        if(blueBoard[i][1]){
            flag1 = true;
        }
    }


    if(flag0&&flag1){
        //2칸
        for(int i=5; i>=2; i--){
            for(int j=0; j<4; j++){
                blueBoard[j][i] = blueBoard[j][i-2];
            }
        }
        for(int k=0; k<4; k++){
            blueBoard[k][0] = 0;
            blueBoard[k][1] = 0;
        }


    }
    else if(flag1){ //1칸
        for(int i=5; i>=1; i--){
            for(int j=0; j<4; j++){
                blueBoard[j][i] = blueBoard[j][i-1];
            }
        }
        for(int k=0; k<4; k++){
            blueBoard[k][0] = 0;
        }

    }

}


int getBlockNum() {
    int blocks = 0;

    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 6; j++) {
            if (blueBoard[i][j]) blocks++;
            if (greenBoard[i][j]) blocks++;
        }
    }



    return blocks;
}


void print(){
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 6; j++) {
            cout << blueBoard[i][j] << ' ';
        }
        cout << '\n';
    }

    cout << "-----------------------\n";

    for(int i=0; i<6; i++){
        for(int j=0; j<4; j++){
            cout << greenBoard[j][i] << ' ';
        }
        cout << '\n';
    }


    cout <<'\n';
    cout << "-----------------------\n";
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N;

    for (int i = 0; i < N; i++) {
        int t, x, y;
        cin >> t >> x >> y;
        buildBlock(t, x, y, blueBoard);
        //90' 회전
        if (t == 2) t = 3;
        else if (t == 3) t = 2;
        buildBlock(t, y, x, greenBoard);

        checkNormalLine(blueBoard);
        checkNormalLine(greenBoard);
        checkSpecialLine(blueBoard);
        checkSpecialLine(greenBoard);
//        print();
    }


    cout << point << '\n';
    cout << getBlockNum() << '\n';

}
반응형
반응형

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

 

17822번: 원판 돌리기

반지름이 1, 2, ..., N인 원판이 크기가 작아지는 순으로 바닥에 놓여있고, 원판의 중심은 모두 같다. 원판의 반지름이 i이면, 그 원판을 i번째 원판이라고 한다. 각각의 원판에는 M개의 정수가 적혀

www.acmicpc.net

1.문제설명

1. 회전하는 함수를 구현한다.

2. 각 원판을 회전 후 인접점을 검사하여 같은 값을 가진 좌표가 있을 경우 해당 지점들은 모두 없앤다.

3. 인접점이 없을 경우 평균을 구해 평균보다 작은 값은 +1 평균보다 큰 값은 모두 -1을 해준다.

 

 

 

1. 회전하는 함수는 deque를 이용하면 쉽게 구현할 수 있다.

2. 인접지점을 검사하는 기능을 구현하는 것이 이 문제의 핵심인데,

규칙을 잘 발견하면 깔끔하게 구할 수 있다.

 

인접지점 중 현재 점과 같은 값을 가진 지점이 존재하는지 검사를 해야하는데

이게 현재 지점이 어떤 점위에 있느냐에 따라 케이스가 나뉘어져

복잡한 if문을 사용해서 풀 수도 있다.

 

그런데 현재 원판이 1번, 2번, ... N번 원판 까지 있으면

가상의 0번 원판, N+1번 원판이 존재한다고 생각하고

해당 원판에 존재하는 수를 모두 0으로 두면

조건을 좀 더 간단하게 만들 수 있다.

 

이런식으로 문제를 풀 수 있는 이유는

문제 조건에서 원판 위의 숫자는 자연수로만 두기 때문에

0과 비교하면 무조건 다른 값을 가진 것으로 나타난다.

 

빨간색 0이 임의로 추가해준 지점이고

파란색 동그라미의 2와 3은 해당 지점에서 인접 지점을 검사할 때

검사할 지점들을 나타낸다

 

이런식으로 구현하면 1번 원판과 N번 원판을 굳이 따로 케이스를 분류하지 않고 풀어도 된다.

 

 


2.문제풀이코드 C++

#include <bits/stdc++.h>

using namespace std;

int N, M, T;
int arr[52][52];

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

void Input();
double getMeans();
void plusMinus();


//row를 k번 돌린다
void rotateClock(int row, int k) {
    deque<int> dq;

    for (int i = 1; i <= M; i++) {
        dq.push_back(arr[row][i]);
    }

    for (int i = 0; i < k; i++) {
        dq.push_front(dq.back());
        dq.pop_back();
    }

    for (int i = 1; i <= M; i++) {
        arr[row][i] = dq.front();
        dq.pop_front();
    }
}

void rotate(int x, int d, int k) {
    for (int i = 1; i <= N; i++) {
        if (i % x == 0) {
            if (d == 0) {
                rotateClock(i, k);
            } else {
                rotateClock(i, M - k);
            }
        }
    }
}

void getAdjacentPoint() {
    vector<pair<int, int> > points;

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            if (arr[i][j] == 0) continue;
            for (int k = 0; k < 4; k++) {
                int nx = i + dx[k];
                int ny = j + dy[k];

                if (ny > M) ny = 1;
                else if (ny < 1) ny = M;

                if (arr[i][j] == arr[nx][ny]) {
                    points.push_back({i, j});
                    points.push_back({nx, ny});
                }
            }
        }
    }

    if (points.size() > 0) {
        for (auto p: points) {
            arr[p.first][p.second] = 0;
        }
    } else {
        plusMinus();
    }
}


double getMeans() {
    int cnt = 0;
    double sum = 0;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            if (arr[i][j] > 0) cnt++;
            sum += arr[i][j];
        }
    }

    if (cnt == 0) return 0;
    else return sum / cnt;
}

void plusMinus() {
    double standard = getMeans();

    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            if (arr[i][j] == 0) continue;

            if (arr[i][j] > standard) {
                arr[i][j]--;
            } else if (arr[i][j] < standard) {
                arr[i][j]++;
            }
        }
    }
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    Input();

    int ans = 0;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            ans += arr[i][j];
        }
    }

    cout << ans << '\n';
}


void Input() {
    cin >> N >> M >> T;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> arr[i][j];
        }
    }

    for (int t = 0; t < T; t++) {
        int x, d, k;
        cin >> x >> d >> k;

        rotate(x, d, k);
        getAdjacentPoint();
    }
}
반응형
반응형

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

 

11559번: Puyo Puyo

총 12개의 줄에 필드의 정보가 주어지며, 각 줄에는 6개의 문자가 있다. 이때 .은 빈공간이고 .이 아닌것은 각각의 색깔의 뿌요를 나타낸다. R은 빨강, G는 초록, B는 파랑, P는 보라, Y는 노랑이다.

www.acmicpc.net

1.문제설명

......
......
......
......
......
......
......
......
.Y....
.YG...
RRYG..
RRYGG.

12 * 6 으로 Input이 주어질 때

같은 색깔인 칸이 상하좌우로 인접하여 4개 이상 있다면 모두 터트려줍니다.

 

......
......
......
......
......
......
......
......
.Y....
.YG...
..YG..
..YGG.

 

 

더이상 터질 수 있는 뿌요가 없다면

중력에 의해 공중에 있는 뿌요는 밑으로 떨어지게 됩니다.

......
......
......
......
......
......
......
......
......
..G...
.YYG..
.YYGG.

 

다시 터트리고 채워주고 반복하면서

터트리는 과정을 몇번 할 수 있는지 세면 되는 문제입니다.

 


2.접근방법[알고리즘]

이 문제는 시뮬레이션 문제로 두가지 과정을 구현해주면 됩니다.

 

1. 뿌요 터트리기

2. 뿌요 떨어트리기

 

 

뿌요 터트리기는 BFS를 돌면서 같은 뿌요가 있다면 몇개있는지 세주고 4개 이상 있다면

같은 뿌요들을 저장해준뒤 char '.'로 바꿔주면 쉽게 구현할 수 있습니다.

 

뿌요 떨어트리기는 for문을 돌면서 맨 아래칸부터 시작하여 위칸을 돌면서

뿌요가 있다면 뿌요가 없는 맨 아래칸과 바꿔주면 됩니다.

 

 

 

처음 주어지는 INPUT이 중력에 의해 떨어진 상태가 아닐수도 있기 때문에

맨 처음 뿌요를 일단 다 떨어트리고 시작해야합니다.

 


 

3.문제풀이코드 C++

 

#include <iostream>
#include <algorithm>
#include <queue>
#include <memory.h>
using namespace std;

string arr[12];
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

void fall() {
	for (int i = 0; i < 6; i++) {
		for (int j = 11; j >= 0; j--) {
			if (arr[j][i] == '.') {
				for (int k = j - 1; k >= 0; k--) {
					if (arr[k][i] != '.') {
						swap(arr[j][i], arr[k][i]);
						break;
					}
				}
			}
		}
	}
}


bool bomb() {
	bool ch[12][6];
	memset(ch, 0, sizeof(ch));
	queue<pair<int, int> > Q;
	bool bombed = false;

	for (int i = 0; i < 12; i++) {
		for (int j = 0; j < 6; j++) {

			if (ch[i][j] == 0 && arr[i][j] != '.') {

				vector<pair<int, int> > v;
				char color = arr[i][j];
				int cnt = 1;
				ch[i][j] = 1;
				v.push_back({ i,j });
				Q.push({ i,j });

				while (!Q.empty()) {
					int x = Q.front().first;
					int y = Q.front().second;
					Q.pop();


					for (int k = 0; k < 4; k++) {
						int nx = x + dx[k];
						int ny = y + dy[k];

						if (nx < 0 || nx >= 12 || ny < 0 || ny >= 6 || ch[nx][ny] == 1) continue;
						if (arr[nx][ny] == color) {
							cnt++;
							ch[nx][ny] = 1;
							Q.push({ nx,ny });
							v.push_back({ nx,ny });
						}
					}
				}

				if (cnt >= 4) {
					bombed = true;
					for (int k = 0; k < v.size(); k++) {
						arr[v[k].first][v[k].second] = '.';
					}
				}
			}
		}
	}

	return bombed;
}



int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);


	for (int i = 0; i < 12; i++) {
		cin >> arr[i];
	}
	// 필드에 뿌요를 모두 두고 일단 떨어트린다. 
	fall();

	//1.터트린다 - 개수 0이면 끝
	//2. 내린다
	//1.2 반복
	int ans = 0;

	while (1) {
		if (bomb()) {
			ans++;
			fall();
		}
		else {
			break;
		}
	}

	cout << ans << '\n';

	return 0;
}

백준 11559번 시간 및 메모리 

 

반응형
반응형

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

 

16918번: 봄버맨

첫째 줄에 R, C, N (1 ≤ R, C, N ≤ 200)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

www.acmicpc.net

1.문제설명

폭탄은 3초가 지나야 터진다.

폭탄이 터지면 폭탄이 있던 자리와 인접한 상하좌우칸이 .이 된다.

폭탄이 터지는 인접 상하좌우에 폭탄이 있을 경우 상하좌우에 있던 폭탄은 그냥 사라진다.

 

 

2.접근방법

3초가 되는 폭탄을 따로 배열이나 벡터에 저장했다가

각각 터트려야 쉽게 구현할 수 있다.

 

만약 3초가 지난 폭탄을 따로 저장하지 않고 순차적으로 터트릴 경우

인접한 3초 폭탄이 사라져 다른 결과를 얻게 된다.

 

다음 표에서 3이 써있는 폭탄은 이제 터지는 폭탄이라고 두고

O는 아직 터지지 않는 폭탄이라 생각하자.

3 3 O
O O O
O O O

 

그냥 무지성으로 3인 폭탄을 for문으로 돌며 터트리면 다음과 같은 결과를 얻는다

X X O
X O O
O O O

오른쪽에 있던 3폭탄이 터지지 못하고 그냥 묻혀버리고 만다.

다른 벡터에 3인 폭탄의 좌표를 모두 저장한 후 벡터에서 for문을 돌면서 터트리면 

X X X
X X O
O O O

이런 옳은 결과를 얻을 수 있다.

 

많은 시뮬레이션 문제에서 이렇게 정보를 저장한 후 실행하는 방법이 유용하게 쓰인다.

 

단순히 순차적으로 돌다보면 문제가 생기는 경우가 많다.

 

 


3.문제풀이코드 C++

 

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

int r, c, n, T;

int a[201][201];
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };


void print() {
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (a[i][j] == -1) {
				cout << '.';
			}
			else cout << 'O';
		}
		cout << '\n';
	}
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> r >> c >> n;

	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			char tmp;
			cin >> tmp;
			if (tmp == 'O') {
				a[i][j] = 0;
			}
			else {
				a[i][j] = -1;
			}
		}
	}
	
	if (T == n) {
		print();
		return 0;
	}


	T++;
	// 첫 1초 아무것도 안함 
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (a[i][j] == 0) {
				a[i][j]++;
			}
		}
	}
	if (T == n) {
		print();
		return 0;
	}

	
	T++;
	//2초 모든칸 폭탄 설치 
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			a[i][j]++;
		}
	}
	if (T == n) {
		print();
		return 0;
	}



	while(T<n) {

		T++;
		vector<pair<int, int> > v;
		
	
		// 아무것도 안함 
		for (int i = 0; i < r; i++) {
			for (int j = 0; j < c; j++) {
				if (a[i][j] >= 0) a[i][j]++;
				if (a[i][j] == 3) {
					v.push_back({ i,j });
				}
			}
		}


		for (int i = 0; i < v.size(); i++) {
			a[v[i].first][v[i].second] = -1;
			for (int k = 0; k < 4; k++) {
				int nx = v[i].first + dx[k];
				int ny = v[i].second + dy[k];
				if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
				a[nx][ny] = -1;
			}
		}

		v.clear();
		if (T == n) break;


		T++;


		// 폭탄 설치 
		for (int i = 0; i < r; i++) {
			for (int j = 0; j < c; j++) {
				a[i][j]++;
				if (a[i][j] == 3) v.push_back({ i,j });
			}
		}
		for (int i = 0; i < v.size(); i++) {
			a[v[i].first][v[i].second] = -1;
			for (int k = 0; k < 4; k++) {
				int nx = v[i].first + dx[k];
				int ny = v[i].second + dy[k];
				if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
				a[nx][ny] = -1;

			}
		}


	}

	
	print();

	return 0;
}

백준 16918 봄버맨

반응형
반응형

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

 

17144번: 미세먼지 안녕!

미세먼지를 제거하기 위해 구사과는 공기청정기를 설치하려고 한다. 공기청정기의 성능을 테스트하기 위해 구사과는 집을 크기가 R×C인 격자판으로 나타냈고, 1×1 크기의 칸으로 나눴다. 구사

www.acmicpc.net

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

int r, c, t, arr[51][51], cleaner;
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };


struct Dust {
	int x, y, q;
};


int ans() {
	int cnt = 0;
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (arr[i][j] > 0) {
				cnt += arr[i][j];
			}
		}
	}
	return cnt;
}


int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> r >> c >> t;


	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == -1) {
				cleaner = i;
			}
		}
	}

	int clean_up = cleaner - 1;
	int clean_down = cleaner;

	//1.미세먼지 확산
	//2. 공기 청정기 이동 
	for (int T = 1; T <= t; T++) {

		vector<Dust> d;

		for (int i = 0; i < r; i++) {
			for (int j = 0; j < c; j++) {
				if (arr[i][j] >= 5) {
					d.push_back({ i,j,arr[i][j] });
				}
			}
		}

		//확산 
		for (int i = 0; i < d.size(); i++) {
			int spread = 0;
			if (d[i].q >= 5) {
				for (int k = 0; k < 4; k++) {
					int nx = d[i].x + dx[k];
					int ny = d[i].y + dy[k];

					if (nx < 0 || nx >= r || ny < 0 || ny >= c) continue;
					if (arr[nx][ny] == -1)continue;
					arr[nx][ny] += (d[i].q / 5);
					spread++;

				}
				arr[d[i].x][d[i].y] -= (d[i].q / 5) * spread;
			}
		}

		// 공기청정기 작동 
		for (int i = clean_up - 1; i >= 0; i--) {
			arr[i + 1][0] = arr[i][0];
		}

		for (int i = clean_down; i < r; i++) {
			arr[i][0] = arr[i + 1][0];

		}

		for (int i = 0; i < c-1; i++) {
			arr[0][i] = arr[0][i + 1];
			arr[r - 1][i] = arr[r - 1][i + 1];
		}

		for (int i = 0; i < clean_up ; i++) {
			arr[i][c - 1] = arr[i + 1][c - 1];
		}

		for (int i = r-1; i > clean_down; i--) {
			arr[i][c - 1] = arr[i - 1][c - 1];
		}

		for (int i = c - 1; i > 1; i--) {
			arr[clean_up][i] = arr[clean_up][i - 1];
			arr[clean_down][i] = arr[clean_down][i - 1];
		}
		arr[clean_up][1] = 0;
		arr[clean_down][1] = 0;


		arr[clean_up][0] = -1;
		arr[clean_down][0] = -1;


	}

	int ans = 0;
	for (int i = 0; i < r; i++) {
		for (int j = 0; j < c; j++) {
			if (arr[i][j] > 0) ans += arr[i][j];
		}
	}

	cout << ans << '\n';

	return 0;
}

백준 17144번 미세먼지 안녕!

반응형
반응형

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

 

14503번: 로봇 청소기

로봇 청소기가 주어졌을 때, 청소하는 영역의 개수를 구하는 프로그램을 작성하시오. 로봇 청소기가 있는 장소는 N×M 크기의 직사각형으로 나타낼 수 있으며, 1×1크기의 정사각형 칸으로 나누어

www.acmicpc.net

1.문제설명

d가 0인 경우에는 북쪽을, 1인 경우에는 동쪽을, 2인 경우에는 남쪽을, 3인 경우 서쪽을 나타낸다.

 

로봇 청소기는 다음과 같이 작동한다.

  1. 현재 위치를 청소한다.
  2. 현재 위치에서 현재 방향을 기준으로 왼쪽 방향부터 차례대로 인접한 칸을 탐색한다.
    1. 왼쪽 방향에 아직 청소하지 않은 공간이 존재한다면, 그 방향으로 회전한 다음 한 칸을 전진하고 1번부터 진행한다.
    2. 왼쪽 방향에 청소할 공간이 없다면, 그 방향으로 회전하고 2번으로 돌아간다.
    3. 네 방향 모두 청소가 이미 되어있거나 벽인 경우에는, 바라보는 방향을 유지한 채로 한 칸 후진을 하고 2번으로 돌아간다.
    4. 네 방향 모두 청소가 이미 되어있거나 벽이면서, 뒤쪽 방향이 벽이라 후진도 할 수 없는 경우에는 작동을 멈춘다.

방향을 전환하면서 이동하면서 청소를 할 수 있는 방의 개수를 찾아야 하는 문제다.

 

 

2.접근 방법[알고리즘]

이 문제를 DFS를 통해 시뮬레이션을 할 때 

종료 조건은 탐색할 수 있는 네 방향 모두 이미 청소되었거나 벽인 경우이고 후진을 할 수 없을 때다.

 

DFS를 돌면서 네방향 모두 체크해주고,

네방향 모두 이미 청소되었거나 벽이라면 

후진을 시켜주고 후진을 할 수 없다면 종료를 시켜준다.

 

종료조건에 해당하지 않는다면

방향전환을 하고, 방향전환시 전진 했을 때 청소가 가능한 방이라면 전진을 시켜준다.

청소가 불가능 한 방이라면 전진하지 않는다.

 

해당 좌표가 이미 방문했던 점이라도 다시 방문해도 상관 없다

위 조건에만 만족하면 된다.

 

DFS코드

void DFS(int x, int y, int d) {
	if (ended) return;
	bool all_cleaned = true;

	//네방향 확인 
	for (int i = 0; i < 4; i++) {
		if (arr[x + dx[i]][y + dy[i]] == 0) {
			all_cleaned = false;
			break;
		}
	}
	if (all_cleaned) {
		// 벽이 있어서 후진 할 수 없다면 종료
		if (arr[x - dx[d]][y - dy[d]] == -1) {
			ended = true;
			return;
		}
		else {
			//후진이 가능할 때
			DFS(x - dx[d], y - dy[d], d);
		}
	}
	// 왼쪽으로 방향 회전 
	int nd = d == 0 ? 3 : d - 1;
	int nx = x + dx[nd];
	int ny = y + dy[nd];

	if (arr[nx][ny] == 0) {
		arr[nx][ny] = ++cleaned;
        //청소 가능한 방이라면 방향전환후 전진
		DFS(nx, ny, nd);
	}
	else {
    	//청소 불가능한 방이라면 방향전환만 
		DFS(x, y, nd);
	}
}

 

 

3.문제풀이코드 C++

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

int n, m, r, c, d, arr[51][51], cleaned;
int dx[4] = { -1,0,1,0 };
int dy[4] = { 0,1,0,-1 };
bool ended = false;

void DFS(int x, int y, int d) {
	if (ended) return;
	bool all_cleaned = true;

	//네방향 확인 
	for (int i = 0; i < 4; i++) {
		if (arr[x + dx[i]][y + dy[i]] == 0) {
			all_cleaned = false;
			break;
		}
	}
	if (all_cleaned) {
		// 벽이 있어서 후진 할 수 없다면 종료
		if (arr[x - dx[d]][y - dy[d]] == -1) {
			ended = true;
			return;
		}
		else {
			//후진이 가능할 때
			DFS(x - dx[d], y - dy[d], d);
		}
	}
	// 왼쪽으로 방향 회전 
	int nd = d == 0 ? 3 : d - 1;
	int nx = x + dx[nd];
	int ny = y + dy[nd];

	if (arr[nx][ny] == 0) {
		arr[nx][ny] = ++cleaned;
		DFS(nx, ny, nd);
	}
	else {
		DFS(x, y, nd);
	}
}


int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;
	cin >> r >> c >> d;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			cin >> arr[i][j];
			if (arr[i][j] == 1) {
				arr[i][j] = -1;
			}
		}
	}
	arr[r][c] = ++cleaned;
	DFS(r, c, d);
	cout << cleaned;
	return 0;
}

백준 14503번 메모리 및 시간

반응형

+ Recent posts