Notice
Recent Posts
Recent Comments
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

코린이 탈출기

[백준 15683] 감시 본문

문제 풀이/DFS

[백준 15683] 감시

명란파스타 2020. 7. 27. 01:17

문제 바로가기

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감��

www.acmicpc.net

청소년 상어 문제 풀면서 제대로 안 읽었다가 호되게 당한 기억이 있어서..

이번 문제는 풀기 전에 충분히 생각하고 풀었다.

 

문제를 풀다보니 대충 생각하고 무작정 코드부터 짜면 로직이 꼬이거나 실수가 많아져서 결국은 시간이 더 오래걸린다는 것을 체득했다.

그래서 ! 이젠 확실히 문제를 이해할 때까지 아이패드에 적어보고 문제에서 요구하는 사항을 완벽히 이해하고 푸는 연습중이다. 이렇게 하니 코드 짜면서 헷갈릴 일이 적어서 오히려 더 빨리 풀 수 있는 것 같다.

 

이 문제도 읽고나서 어떻게 풀어야 할까 고민을 많이 했는데 나는 백트래킹으로 구현을 했다.

cctv의 좌표는 cctv 벡터에 저장했고, dfs 함수에서 cctv가 감시할 수 있는 경우를 for문에서 구해주었다. cctv가 어느 방향을 감시한 후에 그 다음 cctv로 옮겨가서 똑같은 방법으로 수행한다. (재귀 호출)

dfs 함수의 인자인 order == cctv.size()라면, 모든 cctv를 다 봤기 때문에 재귀함수를 빠져나온다. 이 때 사각지대 영역을 계산하고, 현재까지의 min_empty값 보다 작다면 min_empty를 갱신한다.

재귀함수를 빠져나온 이후에는 다시 원래 상태로 돌려주기 위해 copy_map() 함수를 사용했다.

 

 

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int pos[4][2] = { {-1,0},{0,1},{1,0},{0,-1} }; //위, 오른쪽, 아래, 왼쪽
int map[8][8];
int N, M;
int seen[8][8];
int min_empty = 64;
vector<pair<int, int>> cctv;

bool isIn(int x, int y)
{
	if (x >= 0 && x < M && y >= 0 && y < N)
		return true;
	return false;
}
void make_path(int x, int y, int dir)
{
	int nx = x + pos[dir][1];
	int ny = y + pos[dir][0];

	while (isIn(nx, ny) && map[ny][nx] != 6)
	{
		seen[ny][nx] = 1;

		nx = nx + pos[dir][1];
		ny = ny + pos[dir][0];
	}
	
}

void copy_map(int original[8][8], int neww[8][8])
{
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < M; j++)
			neww[i][j] = original[i][j];
	}
}

int find_empty()
{
	int sum = 0;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < M; j++)
		{
			if (seen[i][j] == 0)
				sum++;
		}
	}

	return sum;
}
void dfs(int order)
{
	if (order == cctv.size())
	{
		min_empty = min(min_empty, find_empty());
		return;
	}

	int cy = cctv[order].first;
	int cx = cctv[order].second;
	int c_menu = map[cctv[order].first][cctv[order].second];

	int new_seen[8][8];
	copy_map(seen, new_seen);
		
	if (c_menu == 1)
	{
		for (int i = 0; i < 4; i++)
		{
			make_path(cx, cy, i);
			dfs(order + 1);
			copy_map(new_seen, seen);
		}
	}
	else if (c_menu == 2)
	{
		make_path(cx, cy, 0);
		make_path(cx, cy, 2);
		dfs(order + 1);
		copy_map(new_seen, seen);

		make_path(cx, cy, 1);
		make_path(cx, cy, 3);
		dfs(order + 1);
		copy_map(new_seen, seen);
	}
	else if (c_menu == 3)
	{
		for (int i = 0; i < 4; i++)
		{
			make_path(cx, cy, i);
			make_path(cx, cy, (i + 1) % 4);
			dfs(order + 1);
			copy_map(new_seen, seen);
		}
	}
	else if (c_menu == 4)
	{
		for (int i = 0; i < 4; i++)
		{
			make_path(cx, cy, i);
			make_path(cx, cy, (i + 1) % 4);
			make_path(cx, cy, (i + 2) % 4);
			dfs(order + 1);
			copy_map(new_seen, seen);
		}
	}
	else if (c_menu == 5)
	{
		for (int i = 0; i < 4; i++)
		{
			make_path(cx, cy, i);
		}
		dfs(order + 1);
		copy_map(new_seen, seen);
	}
}

int main()
{
	cin >> N >> M;

	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < M; j++)
		{
			cin >> map[i][j];
			if (map[i][j] >= 1 && map[i][j] < 6)
			{
				seen[i][j] = 1;
				cctv.push_back({ i, j });
			}
			else if (map[i][j] == 6)
				seen[i][j] = 1;
				
		}
	}

	dfs(0);

	cout << min_empty << endl;

	return 0;

}

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

[백준 14889] 스타트와 링크  (0) 2020.07.25
[백준 14888] 연산자 끼워넣기  (0) 2020.07.25
[백준 14891] 톱니바퀴  (0) 2020.07.22
[백준 19236] 청소년 상어  (0) 2020.07.22