[BOJ] 15683번 : 감시

2024. 8. 19. 19:55Algorithm

1. problem : 

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

 

2. solution 1 :

#include <bits/stdc++.h>
using namespace std;
int office[8][8];
int minZero = 1000;
int N, M; // row , col; 
vector<tuple<int, int, int>> v_cctv; // cctv 위치와 종류저장

void xplus_count(int x, int y) {
	while (y < M-1) {
		y++;
		int idx_val = office[x][y]; //x축 양의방향으로 옮겼을 때 들어있는 값;
		if (idx_val == 0) office[x][y] = -1;
		else if (idx_val == 6) return;
		else if (idx_val == -1 || (idx_val > 0 && idx_val < 6)) continue; 
	}
}
void xminus_count(int x, int y) {
	while (y > 0) {
		y--;
		int idx_val = office[x][y]; //x축 음의방향으로 옮겼을 때 들어있는 값;
		if (idx_val == 0) office[x][y] = -1;
		else if (idx_val == 6) return;
		else if (idx_val == -1 || (idx_val > 0 && idx_val < 6)) continue;
	}
}
void yplus_count(int x, int y) {
	while (x < N-1) {
		x++;
		int idx_val = office[x][y]; //y축 양의방향으로 옮겼을 때 들어있는 값;
		if (idx_val == 0) office[x][y] = -1;
		else if (idx_val == 6) return;
		else if (idx_val == -1 || (idx_val > 0 && idx_val < 6)) continue;
	}
}
void yminus_count(int x, int y) {
	while (x > 0) {
		x--;
		int idx_val = office[x][y]; //y축 음의방향으로 옮겼을 때 들어있는 값;
		if (idx_val == 0) office[x][y] = -1;
		else if (idx_val == 6) return;
		else if (idx_val == -1 || (idx_val > 0 && idx_val < 6)) continue;
	}
}

void backTrack(int k) {//param은 감시카메라의 갯수;
	if (k == v_cctv.size()) {
		int zeroCount = 0;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < M; j++) {
				if (office[i][j] == 0) zeroCount++;
			}
		}
		minZero = min(minZero, zeroCount);
		return;
	}
	int x = get<0>(v_cctv[k]);
	int y = get<1>(v_cctv[k]);
	int type = get<2>(v_cctv[k]); 

	// backTrack 후 복구코드 
	int backup[8][8];
	memcpy(backup, office, sizeof(office));
	if (type == 1) {
		xplus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));
		
		xminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		yplus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		yminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));
	}
	else if (type == 2) {
		xplus_count(x, y);
		xminus_count(x, y);
		backTrack(k + 1); 
		memcpy(office, backup, sizeof(office));

		yplus_count(x, y);
		yminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));
	}
	else if (type == 3) {
		xplus_count(x, y);
		yplus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		yplus_count(x, y);
		xminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		xminus_count(x, y);
		yminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		yminus_count(x, y);
		xplus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));
	}
	else if (type == 4) {
		xplus_count(x, y);
		yplus_count(x, y);
		xminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		yplus_count(x, y);
		xminus_count(x, y);
		yminus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		xminus_count(x, y);
		yminus_count(x, y);
		xplus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));

		yminus_count(x, y);
		xplus_count(x, y);
		yplus_count(x, y);
		backTrack(k + 1);
		memcpy(office, backup, sizeof(office));
	}
	else if (type == 5) {
		xplus_count(x, y);
		yplus_count(x, y);
		xminus_count(x, y);
		yminus_count(x, y);
		backTrack(k + 1);
	}

}						
	

int main(void) {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> N >> M;
	
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) {
			cin >> office[i][j];
			if (office[i][j] != 0 && office[i][j] != 6) v_cctv.push_back({ i,j,office[i][j] }); // 감시카메라 위치, 감시카메라 종류 저장
		}
	}
	backTrack(0);
	cout << minZero << '\n';
}

뭔가 비효율적이다. 같은 코드를 더 줄일 수 있을 것 같은데.. 

 

 

3. solution 2 :

// Authored by : BaaaaaaaaaaarkingDog
// Co-authored by : -
// http://boj.kr/c961e6bf6107428caf200c11c964f9e1
#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second

int dx[4] = {1,0,-1,0};
int dy[4] = {0,1,0,-1}; // 남쪽, 동쪽, 북쪽, 서쪽 순서
int n, m;
int board1[10][10]; // 최초에 입력받은 board를 저장할 변수
int board2[10][10]; // 사각 지대의 개수를 세기 위해 사용할 변수
vector<pair<int,int> > cctv; // cctv의 좌표를 저장할 변수

bool OOB(int a, int b){ // Out Of Bounds 확인
  return a < 0 || a >= n || b < 0 || b >= m;
}

// (x,y)에서 dir 방향으로 진행하면서 벽을 만날 때 까지 지나치는 모든 빈칸을 7로 바꿔버림
void upd(int x, int y, int dir){
  dir %= 4;
  while(1){
    x += dx[dir];
    y += dy[dir];
    if(OOB(x,y) || board2[x][y] == 6) return; // 범위를 벗어났거나 벽을 만나면 함수를 탈출
    if(board2[x][y] != 0) continue; // 해당 칸이 빈칸이 아닐 경우(=cctv가 있을 경우) 넘어감
    board2[x][y] = 7; // 빈칸을 7로 덮음
  }
}

int main(void) {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> m;
  int mn = 0; // 사각 지대의 최소 크기 (=답)
  for(int i = 0; i < n; i++){
    for(int j = 0; j < m; j++){
      cin >> board1[i][j];
      if(board1[i][j] != 0 && board1[i][j] != 6)
        cctv.push_back({i,j});
      if(board1[i][j] == 0) mn++;
    }
  }
  // 1 << (2*cctv.size())는 4의 cctv.size()승을 의미.
  for(int tmp = 0; tmp < (1<<(2*cctv.size())); tmp++){ // tmp를 4진법으로 뒀을 때 각 자리수를 cctv의 방향으로 생각할 것이다.
    for(int i = 0; i < n; i++)
      for(int j = 0; j < m; j++)
        board2[i][j] = board1[i][j];
    int brute = tmp;    
    for(int i = 0; i < cctv.size(); i++){
      int dir = brute % 4;
      brute /= 4;
      int x = cctv[i].X;
      int y = cctv[i].Y; // tie(x, y) = cctv[i];로 쓰면 1줄로 줄일 수 있음
      if(board1[x][y] == 1){
        upd(x,y,dir);
      }
      else if(board1[x][y] == 2){
        upd(x,y,dir);
        upd(x,y,dir+2);
      }
      else if(board1[x][y] == 3){
        upd(x,y,dir);
        upd(x,y,dir+1);
      }
      else if(board1[x][y] == 4){
        upd(x,y,dir);
        upd(x,y,dir+1);
        upd(x,y,dir+2);
      }
      else{ // board1[x][y] == 5
        upd(x,y,dir);
        upd(x,y,dir+1);
        upd(x,y,dir+2);
        upd(x,y,dir+3);
      }
    }
    int val = 0;
    for(int i = 0; i < n; i++)
      for(int j = 0; j < m; j++)
        val += (board2[i][j]==0);
    mn = min(mn, val);
  }
  cout << mn;
}

source code 출처 : https://github.com/encrypted-def/basic-algo-lecture/blob/master/0x0D/solutions/15683.cpp

 

basic-algo-lecture/0x0D/solutions/15683.cpp at master · encrypted-def/basic-algo-lecture

바킹독의 실전 알고리즘 강의 자료. Contribute to encrypted-def/basic-algo-lecture development by creating an account on GitHub.

github.com

 

'Algorithm' 카테고리의 다른 글

[BOJ] 12100번 : 2048 (Easy)  (0) 2024.08.20
[BOJ] 18808번 : 스티커 붙이기  (0) 2024.08.20
[BOJ] 16987번 : 계란으로 계란치기  (0) 2024.08.19
[BOJ] 1941번 : 소문난 칠공주  (0) 2024.08.19
[BOJ] 6603번 : 로또  (0) 2024.08.19