728x90
반응형
https://www.acmicpc.net/problem/21608
21608번: 상어 초등학교
상어 초등학교에는 교실이 하나 있고, 교실은 N×N 크기의 격자로 나타낼 수 있다. 학교에 다니는 학생의 수는 N2명이다. 오늘은 모든 학생의 자리를 정하는 날이다. 학생은 1번부터 N2번까지 번호
www.acmicpc.net
최종 코드
GitHub - hwayeon351/BEAKJOON-Algorithms: 백준 알고리즘 소스 코드 모음
백준 알고리즘 소스 코드 모음. Contribute to hwayeon351/BEAKJOON-Algorithms development by creating an account on GitHub.
github.com
//
// main.cpp
// BJ21608_1
//
// Created by Hwayeon on 2021/10/17.
//
#include <iostream>
#include <math.h>
#include <vector>
#include <queue>
using namespace std;
int N;
int room[21][21] = {0, };
struct Student{
int s_id;
int like[4] = {0, };
};
Student st;
Student students[401];
vector<Student> cmds;
struct Seat{
int x;
int y;
int hole = 0;
int like = 0;
};
Seat seat;
struct cmp{
bool operator()(Seat s1, Seat s2){
if(s1.like == s2.like){
if(s1.hole == s2.hole){
if(s1.y == s2.y){
return s1.x > s2.x;
}
return s1.y > s2.y;
}
return s1.hole < s2.hole;
}
return s1.like < s2.like;
}
};
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
int satisfy = 0;
void find_seat(Student st){
priority_queue<Seat, vector<Seat>, cmp> pq;
for(int y=1; y<=N; y++){
for(int x=1; x<=N; x++){
if(room[y][x] > 0) continue;
Seat new_seat;
new_seat.x = x;
new_seat.y = y;
//1. 인접한 좋아하는 학생 수와 빈자리 수 구하기
for(int d=0; d<4; d++){
int nx = x + dx[d];
int ny = y + dy[d];
if(nx<=0 || nx>N || ny<=0 || ny>N) continue;
if(room[ny][nx] == 0) new_seat.hole ++;
else{
for(int i=0; i<4; i++){
if(room[ny][nx] == st.like[i]){
new_seat.like++;
break;
}
}
}
}
//2. 자리 후보 우선순위 큐에 추가
pq.push(new_seat);
}
}
//자리 선정
seat = pq.top();
room[seat.y][seat.x] = st.s_id;
}
void get_satisfy(){
for(int y=1; y<=N; y++){
for(int x=1; x<=N; x++){
int s_id = room[y][x];
int cnt = 0;
//인접한 좋아하는 친구 수 카운트
for(int d=0; d<4; d++){
int nx = x+dx[d];
int ny = y+dy[d];
if(nx<=0 || nx>N || ny<=0 || ny>N) continue;
for(int i=0; i<4; i++){
if(room[ny][nx] == students[s_id].like[i]){
cnt++;
break;
}
}
}
if(cnt == 0) continue;
satisfy += pow(10, cnt-1);
}
}
}
int main(int argc, const char * argv[]) {
cin >> N;
for(int i=1; i<=N*N; i++){
cin >> st.s_id >> st.like[0] >> st.like[1] >> st.like[2] >> st.like[3];
students[st.s_id] = st;
cmds.push_back(st);
}
//모든 학생을 자리에 앉힌다
for(int i=0; i<cmds.size(); i++){
st = cmds[i];
find_seat(st);
}
//만족도 구하기
get_satisfy();
cout << satisfy << endl;
return 0;
}
풀이 과정
풀이 시간 38분
#include <iostream>
#include <math.h>
#include <vector>
#include <queue>
using namespace std;
int N;
int room[21][21] = {0, };
struct Student{
//학생 번호
int s_id;
//좋아하는 4명의 학생 번호를 담는 배열
int like[4] = {0, };
};
Student st;
//students[i] = i번 학생의 정보
Student students[401];
//자리 선정 순서를 담는 벡터
vector<Student> cmds;
struct Seat{
int x;
int y;
//인접한 빈자리 수
int hole = 0;
//인접한 좋아하는 학생 수
int like = 0;
};
Seat seat;
struct cmp{
bool operator()(Seat s1, Seat s2){
//인접한 좋아하는 학생 수가 같은 경우,
if(s1.like == s2.like){
//인접한 빈자리 수가 같은 경우,
if(s1.hole == s2.hole){
//행 번호가 같은 경우,
if(s1.y == s2.y){
//열 번호가 작은 순서대로
return s1.x > s2.x;
}
//행 번호가 작은 순서대로
return s1.y > s2.y;
}
//인접한 빈자리가 많은 순서대로
return s1.hole < s2.hole;
}
//인접한 좋아하는 학생 수가 많은 순서대로
return s1.like < s2.like;
}
};
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
//만족도의 총 합
int satisfy = 0;
void find_seat(Student st){
//후보 자리를 우선순위에 따라 정렬하는 큐
priority_queue<Seat, vector<Seat>, cmp> pq;
for(int y=1; y<=N; y++){
for(int x=1; x<=N; x++){
//빈 자리가 아닌 경우, 학생 st의 자리 후보가 될 수 없다
if(room[y][x] > 0) continue;
//빈 자리인 경우, 새로운 자리 후보이다
Seat new_seat;
new_seat.x = x;
new_seat.y = y;
//1. 인접한 좋아하는 학생 수와 빈자리 수 구하기
for(int d=0; d<4; d++){
int nx = x + dx[d];
int ny = y + dy[d];
//범위를 벗어난 경우, 무시한다
if(nx<=0 || nx>N || ny<=0 || ny>N) continue;
//빈 자리인 경우, 빈자리 수 카운팅
if(room[ny][nx] == 0) new_seat.hole ++;
//다른 학생이 앉아있는 경우, 학생 st가 좋아하는 학생인지 탐색
else{
for(int i=0; i<4; i++){
//좋아하는 학생인 경우, 좋아하는 학생 수 카운팅
if(room[ny][nx] == st.like[i]){
new_seat.like++;
break;
}
}
}
}
//2. 해당 자리 후보 우선순위 큐에 추가
pq.push(new_seat);
}
}
//자리 선정
seat = pq.top();
room[seat.y][seat.x] = st.s_id;
}
void get_satisfy(){
//모든 자리 탐색
for(int y=1; y<=N; y++){
for(int x=1; x<=N; x++){
//s_id = (x, y)에 앉아있는 학생 번호
int s_id = room[y][x];
//인접한 좋아하는 친구 수 카운트
int cnt = 0;
for(int d=0; d<4; d++){
int nx = x+dx[d];
int ny = y+dy[d];
//범위를 벗어난 경우, 무시한다
if(nx<=0 || nx>N || ny<=0 || ny>N) continue;
for(int i=0; i<4; i++){
//좋아하는 학생이 인접해 있다면, 카운팅
if(room[ny][nx] == students[s_id].like[i]){
cnt++;
break;
}
}
}
//인접한 좋아하는 친구가 하나도 없다면 만족도 0
if(cnt == 0) continue;
//인접한 좋아하는 친구가 있는 경우, 만족도 계산
satisfy += pow(10, cnt-1);
}
}
}
int main(int argc, const char * argv[]) {
cin >> N;
for(int i=1; i<=N*N; i++){
cin >> st.s_id >> st.like[0] >> st.like[1] >> st.like[2] >> st.like[3];
//학생 정보를 추가한다
students[st.s_id] = st;
cmds.push_back(st);
}
//모든 학생을 자리에 앉힌다
for(int i=0; i<cmds.size(); i++){
st = cmds[i];
//현재 순서의 학생 st의 자리 선정 -> O(N^2logN)
find_seat(st);
}
//만족도 구하기 -> O(N^2)
get_satisfy();
cout << satisfy << endl;
return 0;
}
//시간복잡도 = O(N^2logN), 공간복잡도 = O(N^2)
이전 풀이
풀이 시간 2시간 5분
#상어 초등학교
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct Seat{
int x;
int y;
int like;
int hole;
};
struct cmp{
bool operator()(Seat a, Seat b){
if(a.like == b.like){
if(a.hole == b.hole){
if(a.y == b.y){
return a.x > b.x;
}
return a.y > b.y;
}
return a.hole < b.hole;
}
return a.like < b.like;
}
};
int N;
//좌, 상, 우, 하
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, -1, 0, 1};
//교실 자리 -> 자리에 배정된 학생 번호를 담는다.
int room[20][20] = {0,};
//자리 배정할 학생 순서 -> order[순서] = 학생 번호
int order_s[400] = {0, };
//학생이 좋아하는 학생의 번호들을 담은 배열
//st[학생 번호] = [번호1, 번호2, 번호3, 번호4]
int st[401][4] = {0,};
long long answer = 0;
int s_num = 0;
int cnt;
Seat s;
int main(int argc, const char * argv[]) {
cin >> N;
for(int i=0; i<N*N; i++){
cin >> s_num;
order_s[i] = s_num;
for(int j=0; j<4; j++){
cin >> st[s_num][j];
}
}
//첫번째 순서인 학생은 (1, 1)에 배정
room[1][1] = order_s[0];
//두번째부터 마지막 학생까지 자리 배정
for(int i=1; i<N*N; i++){
//자리 탐색
//cmp에 맞게 자리가 우선순위에 맞게 정렬된다.
priority_queue<Seat, vector<Seat>, cmp> pq;
for(int y=0; y<N; y++){
for(int x=0; x<N; x++){
//이미 배정된 자리
if(room[y][x]!=0) continue;
//빈 자리인 경우, 인접 자리 탐색
s = {x, y, 0, 0};
int nx, ny;
for(int d=0; d<4; d++){
nx = x+dx[d];
ny = y+dy[d];
if(nx<0 || nx>N-1 || ny<0 || ny>N-1) continue;
//인접 자리가 빈칸인 경우
if(room[ny][nx] == 0){
s.hole++;
}
//인접 자리에 학생이 있는 경우
else{
//현재 학생이 좋아하는 학생인지 체크
for(int k=0; k<4; k++){
if(room[ny][nx] == st[order_s[i]][k]){
s.like++;
break;
}
}
}
}
//해당 자리를 우선순위 큐에 담는다.
pq.push(s);
}
}
//모든 자리 탐색 완료, 우선순위가 가장 높은 자리에 해당 학생을 배정
room[pq.top().y][pq.top().x] = order_s[i];
}
//만족도 조사
for(int y=0; y<N; y++){
for(int x=0; x<N; x++){
cnt = 0;
s_num = room[y][x];
//인접한 자리에 좋아하는 학생이 몇 명 있는지 탐색
for(int d=0; d<4; d++){
int nx = x+dx[d];
int ny = y+dy[d];
if(nx<0 || nx>N-1 || ny<0 || ny>N-1) continue;
for(int i=0; i<4; i++){
if(room[ny][nx] == st[s_num][i]){
cnt ++;
break;
}
}
}
//인접한 좋아하는 학생 수에 따라 만족도 더하기
if(cnt == 1) answer++;
else if(cnt == 2) answer += 10;
else if(cnt == 3) answer += 100;
else if(cnt == 4) answer += 1000;
}
}
cout << answer << endl;
return 0;
}
//시간복잡도 = (N^2logN), 공간복잡도 = O(N^2)
728x90
반응형
'코테 노트 > 백준' 카테고리의 다른 글
백준 14499 주사위 굴리기 C++ (0) | 2021.07.21 |
---|---|
백준 3190 뱀 C++ (0) | 2021.07.19 |
백준 20055 컨베이어 벨트 위의 로봇 C++ (0) | 2021.07.13 |
백준 14501 퇴사 C++ (0) | 2021.07.05 |
백준 13458 시험 감독 C++ (0) | 2021.06.30 |