Algorithm/구현(Brute force, Back tracking, etc.)

백준 21608 상어 초등학교

쩡류 2021. 12. 25. 13:59
728x90

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

 

21608번: 상어 초등학교

상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호

www.acmicpc.net

 

- 빡구현 문제이다. 시간복잡도는 N^2명의 학생이 N^2개의 칸을 순회하면서 자신이 앉을 위치를 찾아나가므로 총 O(N^4)이다.

 

- 일단 student_order배열에 앉을 순서대로 학생들의 번호를 넣고, 학생들을 배치하기 시작한다. 이 과정에서 모든 칸을 순회하면서, 어느 칸에서 좋아하는 학생이 인접 칸에 가장 많이 있는지를 탐색한다. 이 과정에서 벡터에 후보 칸을 모두 담는데, 현재까지 인접 칸의 좋아하는 학생의 최대 수를 계속해서 갱신한다. 갱신 과정은

 

 

  1. 인접 칸의 좋아하는 학생 수 최대 > 현재 칸의 인접 칸의 좋아하는 학생 수 : 후보군이 될 수 없으므로 continue

  2. 인접 칸의 좋아하는 학생 수 최대 == 현재 칸의 인접 칸의 좋아하는 학생 수 : 후보군이 되므로 push_back

  3. 인접 칸의 좋아하는 학생 수 최대 < 현재 칸의 인접 칸의 좋아하는 학생 수 : 벡터를 clear해서 비워주고, 현재 칸을 후보군에 넣는다.

 

- 이 과정을 마치고, vector size가 1이면 해당 학생을 그 칸에 앉히고, 만약 여러 후보가 존재하는 경우 2번 조건인 인접한 칸 중 빈 칸이 가장 많은 자리를 구한다. 이 과정은 위와 동일하게 전개를 해 주면 된다. 

 

- 이 후에도 만약 후보군이 여러 개 존재한다면, sort 메서드를 사용하되 customazing한 compare함수를 넣어 주어서 행이 가장 작은 => 열이 가장 작은 최종 후보를 선택한다.

 

- 문제는 40분만에 풀었지만, 디버깅하는데 거의 30분을 써버렸다. 이유는 for문이 여러 개가 중첩되다보니 j,k를 i,j로 쓰는 실수를 하여 out of bounds 에러가 떴다. ㅠㅠ

 

- 작년 상반기인가 기출문제인데, 합격 컷이 빠르게 제출한 1솔~2솔이라고 한다. 1시간내로 제출을 한다면 충분히 합격권이 가능한 것 같다. 

 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int dx[] = { 0,0,1,-1 };
int dy[] = { -1,1,0,0 };
int map[21][21];
int student_order[401];
int student[401][4];
int n;
void debugging() {
	for (int j = 1; j <= n; j++) {
		for (int k = 1; k <= n; k++) {
			cout << map[j][k] << ' ';
		}
		cout << '\n';
	}
	cout << '\n';
}
bool compare(pair<int, int> a, pair<int, int> b) {
	if (a.first == b.first) {
		return a.second < b.second;
	}
	return a.first < b.first;
}
int main() {
	cin >> n;
	for (int i = 1; i <= n * n; i++) {
		int num; cin >> num;
		student_order[i] = num;
		for (int j = 0; j < 4; j++) {
			cin >> student[num][j];
		}
	}
	for (int i = 1; i <= n*n; i++) {
		int now_student = student_order[i];
		vector<pair<int, int>> area;
		int friend_num = 0;
		for (int j = 1; j <= n; j++) {
			for (int k = 1; k <= n; k++) {
				if (map[j][k]) continue;
				int temp_friend_num = 0;
				for (int l = 0; l < 4; l++) {
					int nx = j + dx[l]; int ny = k + dy[l];
					if (nx < 1 || nx > n || ny < 1 || ny > n) continue;
					if (!map[nx][ny]) continue;
					for (int m = 0; m < 4; m++) {
						if (map[nx][ny] == student[now_student][m]) {
							temp_friend_num++; break;
						}
					}
				}
				if (friend_num > temp_friend_num) continue;
				else if (friend_num == temp_friend_num) area.push_back({ j,k });
				else {
					area.clear();
					friend_num = temp_friend_num;
					area.push_back({ j,k });
				}
			}
		}

		if (area.size() > 1) {
			vector<pair<int, int>> area2;
			int max_blank_num = 0;
			for (int j = 0; j < area.size(); j++) {
				int x = area[j].first; int y = area[j].second;
				int temp_blank_num = 0;
				for (int k = 0; k < 4; k++) {
					int nx = x + dx[k]; int ny = y + dy[k];
					if (nx < 1 || nx > n || ny < 1 || ny > n) continue;
					if (!map[nx][ny]) temp_blank_num++;
				}
				if (max_blank_num > temp_blank_num) continue;
				else if (max_blank_num == temp_blank_num) area2.push_back({ x,y });
				else {
					area2.clear();
					max_blank_num = temp_blank_num;
					area2.push_back({ x,y });
				}
			}
			sort(area2.begin(), area2.end(), compare);
			int answer_x = area2[0].first; int answer_y = area2[0].second;
			map[answer_x][answer_y] = now_student;

		}
		else {
			int answer_x = area[0].first; int answer_y = area[0].second;
			map[answer_x][answer_y] = now_student;
		}
	}
	int answer = 0;
	for (int j = 1; j <= n; j++) {
		for (int k = 1; k <= n; k++) {
			int now_student = map[j][k];
			int friend_num = 0;
			for (int l = 0; l < 4; l++) {
				int nx = j + dx[l]; int ny = k + dy[l];
				if (nx < 1 || nx > n || ny < 1 || ny > n) continue;
				if (!map[nx][ny]) continue;
				for (int m = 0; m < 4; m++) {
					if (map[nx][ny] == student[now_student][m]) {
						friend_num++; break;
					}
				}
			}
			answer += (pow(10, friend_num) / 10);
		}
	}
	cout << answer;
}