본문 바로가기

백준

상어 초등학교

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

백준 21608번: 상어 초등학교 문제 풀이

이 문제는 N x N 크기의 교실에 학생들을 자리 배치하고, 친구들과의 인접도를 기준으로 만족도를 계산하는 문제입니다. 각 학생의 만족도는 인접한 친구의 수에 따라 달라지며, 자리 배치는 아래와 같은 규칙에 따라 이루어집니다.

1.    비어있는 칸 중에서 인접한 친구의 수가 가장 많은 칸 선택
2.    인접한 친구의 수가 같은 칸이 여러 개라면, 인접한 비어있는 칸이 가장 많은 칸 선택
3.    그런 칸도 여러 개라면, 행 번호가 가장 작은 칸 선택
4.    행 번호가 같은 칸이 여러 개라면, 열 번호가 가장 작은 칸 선택

코드 구현

아래는 이 문제의 Java 구현 코드입니다.

import java.io.BufferedReader;  
import java.io.InputStreamReader;  
import java.util.StringTokenizer;  

public class Main {  
    static class Student {  
        int id;  
        int\[\] friend;  

        public Student(int id, int\[\] friend) {  
            this.id = id;  
            this.friend = friend;  
        }  
    }  

    static int N;  
    static int\[\]\[\] map;  
    static int\[\] dx = {-1, 1, 0, 0};  
    static int\[\] dy = {0, 0, -1, 1};  
    static Student\[\] students;  

    public static void main(String\[\] args) throws Exception {  
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));  
        StringTokenizer st;  
        N = Integer.parseInt(br.readLine());  

        students = new Student\[N \* N\];  
        map = new int\[N + 1\]\[N + 1\];  

        // 학생 정보 입력받기  
        for (int i = 0; i < N \* N; i++) {  
            st = new StringTokenizer(br.readLine());  
            int id = Integer.parseInt(st.nextToken());  
            int\[\] friend = new int\[4\];  
            for (int j = 0; j < 4; j++) {  
                friend\[j\] = Integer.parseInt(st.nextToken());  
            }  
            students\[i\] = new Student(id, friend);  
        }  

        // 자리 배치  
        for (Student student : students) {  
            assignSeat(student);  
        }  

        // 만족도 계산 및 출력  
        int totalSatisfaction = 0;  
        for (int i = 1; i <= N; i++) {  
            for (int j = 1; j <= N; j++) {  
                for (int k = 0; k < students.length; k++) {  
                    if (students\[k\].id == map\[i\]\[j\]) {  
                        totalSatisfaction += calc(k, i, j); //학생 인덱스 , x y 좌표를 파라미터로 넘겨서 만족도 계산.  
                    }  
                }  
            }  
        }  
        System.out.println(totalSatisfaction);  
    }  

    private static int calc(int studentNum, int x, int y) {  
        Student student = students\[studentNum\];  
        int score = 0;  
        for (int i = 0; i < 4; i++) {  
            int nx = x + dx\[i\];  
            int ny = y + dy\[i\];  

            if (nx < 1 || nx > N || ny < 1 || ny > N) continue;  

            for (int friendId : student.friend) {  
                if (map\[nx\]\[ny\] == friendId) {  
                    score++;  
                }  
            }  
        }  

        // 만족도 계산  
        if (score == 1) return 1;  
        else if (score == 2) return 10;  
        else if (score == 3) return 100;  
        else if (score == 4) return 1000;  
        else return 0;  
    }  

    private static void assignSeat(Student student) {  
        int x = 0;  
        int y = 0;  
        int maxEmpty = -1;  
        int maxFriend = -1;  

        for (int i = 1; i <= N; i++) {  
            for (int j = 1; j <= N; j++) {  
                if (map\[i\]\[j\] != 0) {  
                    continue;  
                }  
                int emptyCnt = 0;  
                int friendCnt = 0;  

                for (int d = 0; d < 4; d++) {  
                    int nx = i + dx\[d\];  
                    int ny = j + dy\[d\];  

                    // 범위 밖이면 무시  
                    if (nx < 1 || nx > N || ny < 1 || ny > N)  
                        continue;  

                    // 친구가 인접해 있으면 친구 카운트 증가  
                    for (int f : student.friend) {  
                        if (f == map\[nx\]\[ny\]) friendCnt++;  
                    }  

                    // 비어 있는 칸 카운트 증가  
                    if (map\[nx\]\[ny\] == 0) {  
                        emptyCnt++;  
                    }  
                }  
                // 조건에 따른 자리 선택  
                if (friendCnt > maxFriend || (friendCnt == maxFriend && emptyCnt > maxEmpty)) {  
                    x = i;  
                    y = j;  
                    maxEmpty = emptyCnt;  
                    maxFriend = friendCnt;  
                }  
            }  
        }  

        map\[x\]\[y\] = student.id;  
    }  
}  

코드 설명

1.    Student 클래스
•    Student 클래스는 학생의 ID와 친구들을 저장합니다.
•    id: 학생의 ID
•    friend: 친구들의 ID 배열
2.    자리 배치 (assignSeat 메소드)
•    각 학생이 자리에 앉을 때, 위에서 설명한 4가지 조건을 순차적으로 적용하여 최적의 자리를 찾습니다.
•    우선, 비어 있는 자리 중에서 친구가 가장 많은 자리를 선택합니다.
•    그 다음으로, 인접한 빈 자리가 많은 곳을 선택합니다.
•    마지막으로 행과 열의 번호를 기준으로 자리를 결정합니다.
3.    만족도 계산 (calc 메소드)
•    학생의 만족도는 인접한 친구의 수에 따라 1, 10, 100, 1000의 점수를 부여받습니다.
•    각 학생의 위치를 기준으로 주변에 친구가 몇 명 있는지 확인하여 점수를 계산합니다.
4.    전체 만족도 계산
•    모든 학생의 만족도를 계산하여 출력합니다.

문제 해결 과정에서의 어려움

코드를 작성하면서 발생한 어려움은 Student 클래스 배열에서 학생의 ID에 접근할 때 잘못된 인덱스를 사용한 것이었습니다. 이를 해결하기 위해 학생의 ID와 인덱스 간의 관계를 명확히 파악하고 수정하였습니다.

결론

이 문제는 시뮬레이션을 기반으로 하는 문제로, 자리 배치와 만족도 계산을 위한 조건들을 잘 구현하는 것이 핵심입니다. 각 조건을 순차적으로 적용하여 문제를 해결할 수 있었습니다. 작성된 코드는 문제에서 요구하는 대로 자리 배치와 만족도 계산을 올바르게 수행합니다.