ML/AI/SW Developer

BAEK21608 상어 초등학교(C++, Python)

1. 문제 설명

  • 문제 링크
  • NxN 크기의 격자, 학생은 $N^2$ 명
  • 학생들은 선생님이 정해준 순서대로 좌석에 앉음
  • 학생들은 각각 좋아하는 학생 4명이 있음
  • 좌석후보
    1. 비어있는 칸 중에서 좋아하는 학생이 인접한 칸에 가장 많은 칸으로 자리를 정한다.
    2. 1을 만족하는 칸이 여러 개이면, 인접한 칸 중에서 비어있는 칸이 가장 많은 칸으로 자리를 정한다.
    3. 2를 만족하는 칸도 여러 개인 경우에는 행의 번호가 가장 작은 칸으로, 그러한 칸도 여러 개이면 열의 번호가 가장 작은 칸으로 자리를 정한다.
  • 만족도 계산
    • 좋아하는 학생 수: 0 명-> 0 점
    • 좋아하는 학생 수: 1 명-> 1 점
    • 좋아하는 학생 수: 2 명-> 10 점
    • 좋아하는 학생 수: 3 명-> 100 점
    • 좋아하는 학생 수: 4 명-> 1000 점 ``` 조건 첫째 줄에 N이 주어진다. 둘째 줄부터 N2개의 줄에 학생의 번호와 그 학생이 좋아하는 학생 4명의 번호가 한 줄에 하나씩 선생님이 자리를 정할 순서대로 주어진다.

학생의 번호는 중복되지 않으며, 어떤 학생이 좋아하는 학생 4명은 모두 다른 학생으로 이루어져 있다. 입력으로 주어지는 학생의 번호, 좋아하는 학생의 번호는 N2보다 작거나 같은 자연수이다. 어떤 학생이 자기 자신을 좋아하는 경우는 없다.


# 2. 풀이
* 모든 좌석의 정보 탐색, 정보 관리
    * N의 최대값 = 20
    * 학생은 총 400명
        * 학생당 약 좌석 정보 채우기 20x20 => N X N
        * 좌석 정보 기준에 따라 정렬 => NlogN
        * N^2번 반복 => $N^2 \times (N^2 + NlogN)$
        * N은 최대 20 => 약 170,408 시간내에 해결 가능
        * 마지막으로 점수 계산 loop => + N^2 (최대 400자리로 얼마 안됨)
* 문제 조건에 맞추어 착석 가능 좌석 정렬
* 맨 앞에 index 선택

# 3. 코드
* c++

```c++
#include<iostream>
#include<vector>
#include<algorithm>
#include <cstring>

using namespace std;

int N;
vector<int> student[401];
vector<int> list;
int map[21][21];
struct seat {
	int x, y;
	int n_empty = 0;
	int n_prefer = 0;
};

bool comp(seat a, seat b) {
	if (a.n_prefer > b.n_prefer) return true;
	else if (a.n_prefer == b.n_prefer) {
		if (a.n_empty > b.n_empty) return true;
		else if(a.n_empty == b.n_empty){
			if (a.x < b.x) return true;
			else if(a.x == b.x) {
				if (a.y < b.y) return true;
				else return false;
			}
		}
	}
	return false;
}

int dx[4] = { 0,0,-1,1 };
int dy[4] = { 1,-1,0,0 };

int calc(int a) {
	if (a == 4) return 1000;
	else if (a == 3) return 100;
	else if (a == 2) return 10;
	else if (a == 1) return 1;
	else return 0;
}

int main() {
	cin >> N;
	memset(map, 0, sizeof(map));

	// 학생 자리 배치 순서 및 학생 선호도 정보 입력
	for (int i = 0; i < N * N; i++) {
		int st_num;
		cin >> st_num;
		// 학생 자리 배치 순서
		list.push_back(st_num);
		for (int j = 0; j < 4; j++) {
			int temp;
			cin >> temp;
			// 학생 선호도 정보
			student[st_num].push_back(temp);
		}
	}

	// 자리 배치
	for (int i = 0; i < list.size(); i++) {
		// 처음이면 1,1에 자리
		if (i == 0) {
			map[1][1] = list[0];
		}
		// 처음이 아니면
		else {
			// 좌석정보
			vector<seat> candidates;
			int cur_student = list[i];

			// 한칸한칸 좌석 확인해 정보 채우기
			for (int j = 0; j < N; j++) {
				for (int k = 0; k < N; k++) {
					// 이미 앉은 좌석은 후보가 될수 없음
					if (map[j][k] != 0) continue;

					// 현재 좌표
					int cur_x = j;
					int cur_y = k;

					// 선호도 정보
					int prefer = 0;
					for (int z = 0; z < 4; z++) {
						int nx = cur_x + dx[z];
						int ny = cur_y + dy[z];
						if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;
						if (map[nx][ny] == 0) continue;
						for (int t = 0; t < 4; t++) {
							if (student[cur_student][t] == map[nx][ny]) {
								prefer++;
								break;
							}
						}
					}

					// 빈칸 정보
					int empty = 0;
					for (int z = 0; z < 4; z++) {
						int nx = cur_x + dx[z];
						int ny = cur_y + dy[z];
						if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;
						if (map[nx][ny] != 0) continue;
						empty++;
					}

					seat temp;
					temp.x = j;
					temp.y = k;
					temp.n_empty = empty;
					temp.n_prefer = prefer;
					candidates.push_back(temp);
				}
			}
			// 기준에 맞추어 정렬
			if (candidates.size() > 0) {
				sort(candidates.begin(), candidates.end(), comp);
				map[candidates[0].x][candidates[0].y] = cur_student;
			}
		}
	}

	// 점수 계산
	int answer = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			int cur_student = map[i][j];
			int cur_x = i;
			int cur_y = j;
			int pre = 0;
			for (int k = 0; k < 4; k++) {
				int nx = cur_x + dx[k];
				int ny = cur_y + dy[k];
				if (nx < 0 || nx >= N || ny < 0 || ny >= N) continue;
				for (int t = 0; t < 4; t++) {
					if (student[cur_student][t] == map[nx][ny]) {
						pre++;
						break;
					}
				}
			}
			answer += calc(pre);
		}
	}
	cout << answer << endl;

	return 0;
}
  • python
    • 여러 조건으로 리스트 정렬하는 것을 발견하는데 시간이 많이 소요
    • 이런 부분은 c++이 더 간편하지 않나 싶던 와중, 엄청 간단하게 구현이 가능하다는 것을 document를 보고 알 수 있었음… stackover flow 보다 document를 먼저 보자…
# 문제 기준에 맞추어 순서 대로 정렬
# 선호 학생 수, 빈칸 수, x, y
# ((3, True), (2, True), (0, False), (0, False))
def multisort(ls, specs):
    for key, reverse in reversed(specs):
        ls.sort(key=lambda x: x[key], reverse=reverse)
    return ls

# 점수 변환
def ch_score(count):
    if count == 0:
        return 0
    elif count == 1:
        return 1
    elif count == 2:
        return 10
    elif count == 3:
        return 100
    else:
        return 1000

dx = [0, 0, 1, -1]
dy = [1, -1, 0, 0]

# 교실의 한줄 수
N = int(input())
prefer_dic = {}

# 학생들이 앉는 순서
st_order = []

# 좋아하는 학생 정보 저장
for i in range(1, N*N + 1):
    st_num, st1, st2, st3, st4 = map(int,input().split())
    prefer_dic[st_num] = [st1, st2, st3, st4]
    st_order.append(st_num)

# 학생이 앉은 정보 저장할 배열
seated = [[0 for _ in range(N)] for __ in range(N)]

for i, cur_st in enumerate(st_order):
    # 자리에 않는 학생 순서
    if i == 0:
        seated[1][1] = cur_st
    else:
        # 후보좌석 탐색
        candidates = []
        for r in range(N):
            for c in range(N):
                # 좌석이 비어있을 경우에만 진행
                if seated[r][c] == 0:
                    # r, c, 빈좌석수, 좋아하는 학생수
                    temp_info = [r, c, 0, 0]
                    vacant_cnt = 0
                    preferst_cnt = 0
                    # 빈칸 갯수 및 선호 학생 수 검사
                    for d in range(4):
                        nr = r + dx[d]
                        nc = c + dy[d]
                        # 교실의 좌표를 벗어나지 않으면
                        if 0 <= nr < N and 0 <= nc < N: 
                            # 빈칸이면 빈칸 수 증가
                            if seated[nr][nc] == 0:
                                vacant_cnt += 1
                            # 선호 학생이면 선호 학생 수 증가
                            elif seated[nr][nc] in prefer_dic[cur_st]:
                                preferst_cnt += 1
                    temp_info[2] = vacant_cnt
                    temp_info[3] = preferst_cnt
                    candidates.append(temp_info)
        # 기준에 맞추어 정렬
        
        candidates = multisort(candidates, ((3, True), (2, True), (0, False), (0, False)))
        seated[candidates[0][0]][candidates[0][1]] = cur_st

# 점수 계산
score = 0
for r in range(N):
    for c in range(N):
        cur_st = seated[r][c]
        count = 0
        for d in range(4):
            nr = r + dx[d]
            nc = c + dy[d]
            # 교실의 좌표를 벗어나지 않으면
            if 0 <= nr < N and 0 <= nc < N: 
                if seated[nr][nc] in prefer_dic[cur_st]:
                    count += 1
        score += ch_score(count)

print(score)

4. 결과


python 연습. 입력받는 법이 C++과 다르고, 인자를 주고받는 방식이 다르기때문에 익숙해지는 것에 시간이 필요할 것 같다.