거의 알고리즘 일기장

백준 15683번_ 감시 본문

알고리즘 문제풀이

백준 15683번_ 감시

건우권 2020. 5. 1. 15:30

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

 

15683번: 감시

스타트링크의 사무실은 1×1크기의 정사각형으로 나누어져 있는 N×M 크기의 직사각형으로 나타낼 수 있다. 사무실에는 총 K개의 CCTV가 설치되어져 있는데, CCTV는 5가지 종류가 있다. 각 CCTV가 감시할 수 있는 방법은 다음과 같다. 1번 CCTV는 한 쪽 방향만 감시할 수 있다. 2번과 3번은 두 방향을 감시할 수 있는데, 2번은 감시하는 방향이 서로 반대방향이어야 하고, 3번은 직각 방향이어야 한다. 4번은 세 방향, 5번은 네 방향을 감시할

www.acmicpc.net

풀이방법

 1. cctv를 기준으로 left, right, up, down을 채울수 있는 함수 4개를 만든다. (밑의 코드참조)

void fillup(pair<int, int>pos, vector<vector<int>>& calmap)
{
	while (1)
	{
		pos.first -= 1;
		if (pos.first < 0)
			break;
		
		if (calmap[pos.first][pos.second] == 0)
			calmap[pos.first][pos.second] = 7;
		else if (calmap[pos.first][pos.second] == 6)
			break;
	}
}
//... 나머지 down, left, right도 이런식으로 만들면 된다.

 

 2. dfs를 이용해서 방향 선택의 모든 경우의 수를 모두 돌리고 빈 공간을 계산한다.

 

ex) cctv1이면 상, 하, 좌, 우로 4가지 경우가 나올수 있음,  cctv2이면 상하, 좌우로 2가지 경우가 나올수 있음 ....


 전체코드

#include <iostream>
#include <algorithm>
#include <vector>
#include <limits.h>

using namespace std;

class cctvInformation
{
public:
	int y;
	int x;
	int cctvtype;

	cctvInformation(int y_in, int x_in, int cctvtype_in)
		:y(y_in), x(x_in), cctvtype(cctvtype_in)
	{}
};

int n, m;
vector<vector<int>> map;
vector<cctvInformation> cctv;

void fillup(pair<int, int>pos, vector<vector<int>>& calmap)
{
	while (1)
	{
		pos.first -= 1;
		if (pos.first < 0)
			break;
		
		if (calmap[pos.first][pos.second] == 0)
			calmap[pos.first][pos.second] = 7;
		else if (calmap[pos.first][pos.second] == 6)
			break;
	}
}

void filldown(pair<int, int>pos, vector<vector<int>>& calmap)
{
	while (1)
	{
		pos.first += 1;
		if (pos.first >= n)
			break;

		if (calmap[pos.first][pos.second] == 0)
			calmap[pos.first][pos.second] = 7;
		else if (calmap[pos.first][pos.second] == 6)
			break;
	}
}

void fillleft(pair<int, int>pos, vector<vector<int>>& calmap)
{
	while (1)
	{
		pos.second -= 1;
		if (pos.second < 0)
			break;

		if (calmap[pos.first][pos.second] == 0)
			calmap[pos.first][pos.second] = 7;
		else if (calmap[pos.first][pos.second] == 6)
			break;
	}
}

void fillright(pair<int, int>pos, vector<vector<int>>& calmap)
{
	while (1)
	{
		pos.second += 1;
		if (pos.second >= m)
			break;

		if (calmap[pos.first][pos.second] == 0)
			calmap[pos.first][pos.second] = 7;
		else if (calmap[pos.first][pos.second] == 6)
			break;
	}
}

int minValue = INT_MAX;
int getEmptyPlace(vector<vector<int>> calmap)
{
	int cnt = 0;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < m; j++)
			if (calmap[i][j] == 0)
				cnt++;

	return cnt;
}

void dfs(vector<vector<int>>calmap, int cnt)
{
	if (cnt == cctv.size())
	{
		//check
		minValue = min(minValue, getEmptyPlace(calmap));
		return;
	}

	//check cctvtype
	int cctvtype = cctv[cnt].cctvtype;
	pair<int, int>pos = { cctv[cnt].y, cctv[cnt].x };

	//cctvtype에 따라 다르게 dfs보냄
	if (cctvtype == 1)
	{
		vector<vector<int>>nextcalmap = calmap;

		//1은 4가지경우가 있음
		fillup(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		filldown(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		fillleft(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		fillright(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

	}

	else if (cctvtype == 2)
	{
		vector<vector<int>>nextcalmap = calmap;

		//2은 2가지경우가 있음
		fillup(pos, nextcalmap);
		filldown(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		fillleft(pos, nextcalmap);
		fillright(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);
	}

	else if (cctvtype == 3)
	{
		vector<vector<int>>nextcalmap = calmap;

		//3은 4가지경우가 있음
		fillup(pos, nextcalmap);
		fillleft(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		filldown(pos, nextcalmap);
		fillleft(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		filldown(pos, nextcalmap);
		fillright(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		fillright(pos, nextcalmap);
		fillup(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);
	}

	else if (cctvtype == 4)
	{
		vector<vector<int>>nextcalmap = calmap;

		//4은 4가지경우가 있음
		fillup(pos, nextcalmap);
		fillleft(pos, nextcalmap);
		fillright(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		filldown(pos, nextcalmap);
		fillleft(pos, nextcalmap);
		fillup(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		fillleft(pos, nextcalmap);
		filldown(pos, nextcalmap);
		fillright(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);

		nextcalmap = calmap;
		fillright(pos, nextcalmap);
		fillup(pos, nextcalmap);
		filldown(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);
	}

	else if (cctvtype == 5)
	{
		vector<vector<int>>nextcalmap = calmap;

		//5은 1가지경우가 있음
		fillup(pos, nextcalmap);
		fillleft(pos, nextcalmap);
		fillright(pos, nextcalmap);
		filldown(pos, nextcalmap);
		dfs(nextcalmap, cnt + 1);
	}
}


int main()
{
	map.resize(9);
	for (int i = 0; i < 8; i++)
		map[i].resize(9);

	cin >> n >> m;

	for (int i = 0; i < n; i++)
	{
		int value;
		for (int j = 0; j < m; j++)
		{
			cin >>  value;
			map[i][j] = value;

			//cctv 위치, 타입 저장
			if (value != 0 && value != 6)
			{
				cctv.push_back(cctvInformation(i, j, value));
			}
		}
	}

	dfs(map, 0);

	cout << minValue;

	return 0;
}

 후기

 함수를 배열화 시켜서 dfs를 반복문을 통해 간단하게 다시 짜서 올리고 싶었는데 짜다가 너무 귀찮아져서 그냥 예전에 하드코딩했던 코드를 올린다. 이렇게 짜지말고 dir[] = {{u,d,l,r}, {ud, lr}....} 이런식으로 짤것.

 

반응형

'알고리즘 문제풀이' 카테고리의 다른 글

백준 11657번 _ 타임머신  (0) 2020.05.03
codeforces_ 158B_ Taxi  (0) 2020.05.02
백준 14891번 _ 톱니바퀴  (0) 2020.04.30
백준 14890번_경사로  (0) 2020.04.30
백준 14889번 _ 스타트와 링크  (0) 2020.04.29
Comments