[BOJ 21608] 상어 초등학교
업데이트:
문제
- BOJ 21608
- 문제의 저작권은 Baekjoon Online Judge에 있습니다.
접근방식
실버1이라서 쉬울 줄 알았는데 런타임에러가 나와서 보니까 처음에는 likeCnt!=0 || zeroCnt!=0
인 좌표들만 pq
에 넣어줬는데 그렇게 되면 마지막 번호이고 주변에 likeCnt
가 없는 경우는 pq
에 값이 안들어가므로 poll()
했을 때 에러가 발생한다.
그래서 모든 경우에 대해 pq
에 넣어주니 해결되는 문제였다.
findSeat(int num
에서 학생 순서대로 자리를 찾는다.- 좌표 1,1부터 N,N까지 돌면서 4방향 탐색을 하면서 인접한 칸에 존재하는 좋아하는 수, 빈칸 수를 기록하고
pq
에 넣는다. - 모든 조사가 끝나면
pq
에서 하나 꺼내서 자리를 확정짓는다.
pq
의 타입은Point
클래스인데 여기서Comparable
로 1)좋아하는 학생이 많은 순, 2)빈칸이 많은 순, 3)행과 열이 작은 순으로 정렬해주므로 이를 모두 만족하는 자리가 꺼내진다.
- 좌표 1,1부터 N,N까지 돌면서 4방향 탐색을 하면서 인접한 칸에 존재하는 좋아하는 수, 빈칸 수를 기록하고
- 모든 학생의 자리를 찾았으면 map을 돌면서
getSatisfy(int i, int j)
에서 주변에 인접한 좋아하는 학생 수를 카운트해서 그에 따른 만족도를Ans
에 누적합한다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
public class Main {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StringTokenizer st;
static int[] satisfy = { 0, 1, 10, 100, 1000 }; // 만족도
static int N;
static int[][] map; // 확정된 학생 자리
static PriorityQueue<Point> pq;
static int[][][] students; // i:현재번호, j:전체 번호, k:좋아하면 1,아니면 0
static int[] order; // 자리 정하는 순서
static int sCnt; // 학생 수
static int[][] dArr = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
static int Ans; // 만족도 합
static class Point implements Comparable<Point> {
int x, y;
int likeCnt; // 인접해있는 좋아하는 사람 수
int zeroCnt; // 인접해있는 빈칸 수
public Point(int x, int y, int likeCnt, int zeroCnt) {
this.x = x;
this.y = y;
this.likeCnt = likeCnt;
this.zeroCnt = zeroCnt;
}
@Override
public int compareTo(Point o) {
if (this.likeCnt == o.likeCnt) { // 1. 좋아하는 학생이 많은 순
if (this.zeroCnt == o.zeroCnt) { // 2. 빈칸이 많은 순
if (this.x == o.x)
return Integer.compare(this.y, o.y); // 3. 행,열 작은순
else
return Integer.compare(this.x, o.x);
} else
return Integer.compare(o.zeroCnt, this.zeroCnt);
} else
return Integer.compare(o.likeCnt, this.likeCnt);
}
}
public static void main(String[] args) throws IOException {
N = Integer.parseInt(br.readLine());
map = new int[N + 1][N + 1];
sCnt = (int) Math.pow(N, 2);
students = new int[sCnt + 1][(int) (sCnt + 1)][1];
order = new int[sCnt + 1];
for (int i = 1; i <= sCnt; i++) {
st = new StringTokenizer(br.readLine());
int num = Integer.parseInt(st.nextToken()); // 번호
for (int j = 0; j < 4; j++) {// 좋아하는 학생 번호
int likeNum = Integer.parseInt(st.nextToken());
students[num][likeNum][0] = 1;
order[i] = num;
}
} // End input
for (int k = 1; k <= sCnt; k++) { // 각 학생의 자리 구하기
int num = order[k];
findSeat(num);
}
// 자리 확정 후 만족도의 총 합 구하기
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
Ans += satisfy[getSatisfy(i, j)];
}
}
System.out.println(Ans);
}
private static int getSatisfy(int i, int j) {
int likeCnt = 0;
for (int d = 0; d < 4; d++) {
int nx = i + dArr[d][0];
int ny = j + dArr[d][1];
if (nx >= 1 && nx <= N && ny >= 1 && ny <= N) {
if (students[map[i][j]][map[nx][ny]][0] == 1)
likeCnt++;
}
}
return likeCnt;
}
private static void findSeat(int num) {
pq = new PriorityQueue<>();
for (int i = 1; i <= N; i++) { // 모든 칸 조사
for (int j = 1; j <= N; j++) {
if (map[i][j] != 0) continue;
// 인접한 칸에 좋아하는 학생이 있는지 확인
int likeCnt = 0;
int zeroCnt = 0;
for (int d = 0; d < 4; d++) {
int nx = i + dArr[d][0];
int ny = j + dArr[d][1];
if (nx >= 1 && nx <= N && ny >= 1 && ny <= N) {
// 좋아하는 학생있는지
if (students[num][map[nx][ny]][0] == 1)
likeCnt++;
else if (map[nx][ny] == 0)
zeroCnt++;
}
} // 인접칸 조사 끝
pq.add(new Point(i, j, likeCnt, zeroCnt)); // 후보로 넣음
}
}
// 확정 자리 하나 꺼내기
Point p = pq.poll();
map[p.x][p.y] = num;
}
}