문제
상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N^2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N^2번까지 번호가 매겨져 있고, (r, c)는 r행 c열을 의미한다. 교실의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다.
선생님은 학생의 순서를 정했고, 각 학생이 좋아하는 학생 4명도 모두 조사했다. 이제 다음과 같은 규칙을 이용해 정해진 순서대로 학생의 자리를 정하려고 한다. 한 칸에는 학생 한 명의 자리만 있을 수 있고, |r1 - r2| + |c1 - c2| = 1을 만족하는 두 칸이 (r1, c1)과 (r2, c2)를 인접하다고 한다.
- 비어있는 칸 중에서 좋아하는 학생이 인접한 칸에 가장 많은 칸으로 자리를 정한다.
- 1을 만족하는 칸이 여러 개이면, 인접한 칸 중에서 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
- 2를 만족하는 칸도 여러 개인 경우에는 행의 번호가 가장 작은 칸으로, 그러한 칸도 여러 개이면 열의 번호가 가장 작은 칸으로 자리를 정한다.
예를 들어, N = 3이고, 학생 N^2명의 순서와 각 학생이 좋아하는 학생이 다음과 같은 경우를 생각해보자.
학생의 번호 | 좋아하는 학생의 번호 |
4 | 2, 5, 1, 7 |
3 | 1, 9, 4, 5 |
9 | 8, 1, 2, 3 |
8 | 1, 9, 3, 4 |
7 | 2, 3, 4, 8 |
1 | 9, 2, 5, 7 |
6 | 5, 2, 3, 4 |
5 | 1, 9, 2, 8 |
2 | 9, 3, 1, 4 |
가장 먼저, 4번 학생의 자리를 정해야 한다. 현재 교실의 모든 칸은 빈 칸이다. 2번 조건에 의해 인접한 칸 중에서 비어있는 칸이 가장 많은 칸인 (2, 2)이 4번 학생의 자리가 된다.
4 | ||
다음 학생은 3번이다. 1번 조건을 만족하는 칸은 (1, 2), (2, 1), (2, 3), (3, 2) 이다. 이 칸은 모두 비어있는 인접한 칸이 2개이다. 따라서, 3번 조건에 의해 (1, 2)가 3번 학생의 자리가 된다.
3 | ||
4 | ||
다음은 9번 학생이다. 9번 학생이 좋아하는 학생의 번호는 8, 1, 2, 3이고, 이 중에 3은 자리에 앉아있다. 좋아하는 학생이 가장 많이 인접한 칸은 (1, 1), (1, 3)이다. 두 칸 모두 비어있는 인접한 칸이 1개이고, 행의 번호도 1이다. 따라서, 3번 조건에 의해 (1, 1)이 9번 학생의 자리가 된다.
9 | 3 | |
4 | ||
이번에 자리를 정할 학생은 8번 학생이다. (2, 1)이 8번 학생이 좋아하는 학생과 가장 많이 인접한 칸이기 때문에, 여기가 그 학생의 자리이다.
9 | 3 | |
8 | 4 | |
7번 학생의 자리를 정해보자. 1번 조건을 만족하는 칸은 (1, 3), (2, 3), (3, 1), (3, 2)로 총 4개가 있고, 비어있는 칸과 가장 많이 인접한 칸은 (2, 3), (3, 2)이다. 행의 번호가 작은 (2, 3)이 7번 학생의 자리가 된다.
9 | 3 | |
8 | 4 | 7 |
이런식으로 학생의 자리를 모두 정하면 다음과 같다.
9 | 3 | 2 |
8 | 4 | 7 |
5 | 6 | 1 |
이제 학생의 만족도를 구해야 한다. 학생의 만족도는 자리 배치가 모두 끝난 후에 구할 수 있다. 학생의 만족도를 구하려면 그 학생과 인접한 칸에 앉은 좋아하는 학생의 수를 구해야 한다. 그 값이 0이면 학생의 만족도는 0, 1이면 1, 2이면 10, 3이면 100, 4이면 1000이다.
학생의 만족도의 총 합을 구해보자.
시간 제한: 1초
메모리 제한: 1024MB
입력
첫째 줄에 N이 주어진다. 둘째 줄부터 N^2개의 줄에 학생의 번호와 그 학생이 좋아하는 학생 4명의 번호가 한 줄에 하나씩 선생님이 자리를 정할 순서대로 주어진다.
학생의 번호는 중복되지 않으며, 어떤 학생이 좋아하는 학생 4명은 모두 다른 학생으로 이루어져 있다. 입력으로 주어지는 학생의 번호, 좋아하는 학생의 번호는 N^2보다 작거나 같은 자연수이다. 어떤 학생이 자기 자신을 좋아하는 경우는 없다.
• 3 ≤ N ≤ 20
출력
첫째 줄에 학생의 만족도의 총 합을 출력한다.
예제 입력 | 예제 출력 |
3
4 2 5 1 7
3 1 9 4 5
9 8 1 2 3
8 1 9 3 4
7 2 3 4 8
1 9 2 5 7
6 5 2 3 4
5 1 9 2 8
2 9 3 1 4 | 54 |
3
4 2 5 1 7
2 1 9 4 5
5 8 1 4 3
1 2 9 3 4
7 2 3 4 8
9 8 4 5 7
6 5 2 3 4
8 4 9 2 1
3 9 2 1 4 | 1053 |
풀이
첫번째 조건은 인접한 위치의 학생이 좋아하는 학생 배열 에 있는지 pair배열을 활용해 검사하고,
그 값이 가장 큰 것을 배열에 저장하도록 구현했다.
두번째 조건은 배열에서 x값이 가장 작은 값들을 배열에 추가하도록 구현했다.
세번째 조건은 배여에서 y값이 가장 작은 값을 배열에 추가하도록 구현했다.
배열의 크기를 검사해 각 조건 실행 여부를 판단했다.
인접한 위치는 dx dy 배열을 사용해 원점의 좌표와 연산 후 각 조건에 맞게 배치하였고, 자리에 모든 학생이 채워져야만 만족도를 계산할 수 있어, 자리를 채우는 단계와 만족도 계산 단계로 나누어서 풀었다.
메모리 제한이 널널해 각 항목을 저장하는 배열을 마음껏 사용하였다.
코드
#include <iostream> #include <algorithm> #include <vector> using namespace std; int dx[4] = {0, 1, 0, -1}; int dy[4] = {1, 0, -1, 0}; int pp[5] = {0, 1, 10, 100, 1000}; void Solution(vector<vector<int>>& matrix, const vector<int>& student, const vector<vector<int>>& prefer, int n) { vector<pair<int, int>> location; for (int std = 0; std < n * n; ++std) { int target = student[std]; int largest = 0; for (int i = 0; i < n; ++i) { // first rule for (int j = 0; j < n; j++) { if (matrix[i][j] == -1) { int cnt = 0; for (int dir = 0; dir < 4; ++dir) { int nx = i + dx[dir]; // index check int ny = j + dy[dir]; if (nx >= n || ny >= n || nx < 0 || ny < 0) continue; if (find(prefer[target].begin(), prefer[target].end(), matrix[nx][ny]) != prefer[target].end()) { cnt += 1; } } if (largest < cnt) { location.clear(); location.emplace_back(i, j); largest = cnt; } else if (largest == cnt) { location.emplace_back(i, j); } cnt = 0; } } } if (location.size() > 1) { // second rule vector<pair<int, int>> nlocation; int largest = 0; int index = 0; for (int i = 0; i < location.size(); ++i) { int cnt = 0; for (int dir = 0; dir < 4; ++dir) { int nx = location[i].first + dx[dir]; int ny = location[i].second + dy[dir]; if (nx >= n || ny >= n || nx < 0 || ny < 0) continue; if (matrix[nx][ny] == -1) cnt += 1; } if (largest < cnt) { nlocation.clear(); nlocation.emplace_back(location[i].first, location[i].second); largest = cnt; } else if (largest == cnt) { nlocation.emplace_back(location[i].first, location[i].second); } cnt = 0; } location = nlocation; } if (location.size() > 1) { // third rule int sx = 400; vector<pair<int, int>> nlocation; for (int i = 0; i < location.size(); ++i) { if (location[i].first < sx) { nlocation.clear(); nlocation.emplace_back(location[i].first, location[i].second); sx = location[i].first; } else if (location[i].first == sx) { nlocation.emplace_back(location[i].first, location[i].second); } } location = nlocation; } if (location.size() > 1) { int sy = 400; pair<int, int> tmp; for (int i = 0; i < location.size(); ++i) { if (location[i].second < sy) { tmp = location[i]; sy = location[i].second; } } location.clear(); location.push_back(tmp); } matrix[location[0].first][location[0].second] = target; location.clear(); } } int Calculate(const vector<vector<int>>& matrix, const vector<int>& student, const vector<vector<int>>& prefer, int n) { int result = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { int score = 0; for (int k = 0; k < 4; ++k) { int nx = dx[k] + i; // index check int ny = dy[k] + j; if (nx >= n || ny >= n || nx < 0 || ny < 0) continue; if (find(prefer[matrix[i][j]].begin(),prefer[matrix[i][j]].end(), matrix[nx][ny]) != prefer[matrix[i][j]].end()) { score += 1; } } result += pp[score]; } } return result; } int main() { int n; cin >> n; vector<int> student(n * n); vector<vector<int>> prefer(n*n+1, vector<int>(4)); vector<vector<int>> matrix(n, vector<int>(n, -1)); for (int i = 0; i < n * n; ++i) { int index; cin >> index; student[i] = index; for (int j = 0; j < 4; ++j) { cin >> prefer[index][j]; } } Solution(matrix, student, prefer, n); cout << Calculate(matrix, student, prefer, n); return 0; }