Algorithm/카카오기출

[프로그래머스] 거리두기 확인하기

StrongMin 2022. 6. 6. 22:35

문제

풀이

#include <string>
#include <vector>
#include <string.h> // memset
using namespace std;
bool visited[5][5];

int dx[4];
int dy[4];
bool isSafe ;
void dfs(int y, int x, vector<string> place, int count){
    visited[y][x] = true;
    if(count>2 || place[y][x] == 'X') {
        return;
    }
    else {
        if(count !=0 && place[y][x] == 'P') {
            isSafe =false; 
            return;
        }
    
        for(int i=0; i<4; i++){
            int px = x+dx[i];
            int py = y+dy[i];
            if((px>=0&&py>=0) && (px<5 && py<5)){
                if(!visited[py][px]){
                    visited[py][px] = true;
                    dfs(py,px,place,count+1);
                    visited[py][px] = false; // 없애면 오류
                }
            }
        }
    }
}

//탐색으로 풀기
vector<int> solution(vector<vector<string>> places) {
    vector<int> answer;
    dx[0] = 1; dx[1] = 0; dx[2] = -1; dx[3] = 0;
    dy[0] = 0; dy[1] = 1; dy[2] = 0; dy[3] = -1;
    for(vector<string> place : places){
        isSafe = true;
        memset(visited, false, sizeof(visited));
        for(int y=0; y<5; y++){
            for(int x=0; x<5; x++){
               if(place[y][x] == 'P'){
                    dfs(y, x, place, 0);
                    if(!isSafe) break;
                } 
            }
            if(!isSafe) break;
        }
        isSafe==true?answer.push_back(1) : answer.push_back(0);
    }
    return answer;
}

 

해결 방법

 

1. 'P'를 발견하면 상하좌우로 깊이 탐색

2. 깊이 탐색을 돌고 그때마다 count를 세어주어 2 이상일 경우 (사람 간의 거리가 2 이상일 경우)와

    탐색 도중 'X'를 발경 할 경우(사람과 사람 사이에 칸막이가 있는 경우)는 조건을 만족하므로 제외

3. count가 2 미만이고, 'P'가 발견될 경우(사람 간의 사이가 2미터가 되지 않는 경우)

    return값으로 false를 주어 반복문을 빠져나온다.

4. false로 인해 반복문을 빠져나온 경우는 0을, 정상적으로 빠져나온 경우는 1을 정답배열에 삽입한다.

 

 

 

 


다른 사람 풀이

#include <string>
#include <vector>
#include <iostream>

using namespace std;

/*
"POOOP",
"OXXOX", 
"OPXPX",
"OOXOX",
"POXXP"
*/

bool is_valid_place(const vector<string>& place)
{
    constexpr size_t N = 5;

    vector<vector<int>> is_in_use(
        N,
        vector<int>(N, false)
    );

    int di[] = {1,-1,0,0};
    int dj[] = {0,0,1,-1};

    for(size_t i=0; i!=N; ++i)
        for(size_t j=0; j!=N; ++j)
            if(place[i][j] == 'P'){
                for(size_t k=0; k!=4; ++k){
                    size_t moved_i = i + di[k];
                    size_t moved_j = j + dj[k];

                    if(moved_i >= N || moved_j >= N)
                        continue;

                    switch(place[moved_i][moved_j]){
                        case 'P':
                            return false;
                        case 'O':
                            if(is_in_use[moved_i][moved_j])
                                return false;

                            is_in_use[moved_i][moved_j] = true;
                            break;
                        case 'X':
                            break;
                    }
                }
            }

    return true;
}

vector<int> solution(vector<vector<string>> places) {
    vector<int> answer(5);
    for(size_t i=0; i!=5; ++i)
        answer[i] = is_valid_place(places[i]);
    return answer;
}

 

 

case 'O':
	if(is_in_use[moved_i][moved_j])
		return false;

	is_in_use[moved_i][moved_j] = true;
	break

이 부분이 이해가 가지 않았다가, 놀란 부분인데

이미 O주위에 사람이 있었다면, true로 바뀌었을 것이기 때문에

count를 세주지 않아도 주위에 P가 있다는 것(거리두기 수칙을 지키지 않은 것)을 알 수 있었다!

 

다른 사람들의 아이디어를 보는 건 정말 공부가 된다.