티스토리 뷰
https://www.acmicpc.net/problem/25383
25383번: 주사위
첫 번째 줄에 두 정수 $H$, $W$가 주어진다. 이후, $H$개의 줄에 걸쳐, 큰 종이에 그려진 전개도들이 주어진다. 각 줄에 길이 $W$의 문자열이 주어지며, 이 문자열은 '.', 'x', '-', '|', '+'의 문자들로만
www.acmicpc.net
어제 다 푼 문제인데,
코드가 지저분하니까 어디서 잘못된건지를 잘 몰라서 이곳 저곳 수정하다가 겨우 에러가 발생하는 지점을 찾았다. 주사위 변형하는 부분에 오류가 있을 줄 알았는데, 제일 처음 주사위 만들 때 실수가 있었다. 오늘이라도 발견해서 다행이다.
푼 사람이 별로 없는 문제라서
Node로 이 문제 푼 사람 중에 1등이다🙂. 벽이라고 느껴지던 플레 1문제를 혼자 힘으로 풀었다는 게 더 기쁘다
class Node {
constructor(item) {
this.item = item;
this.next = null;
}
}
class Queue {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
push(item) {
const node = new Node(item);
if (this.head == null) {
this.head = node;
} else {
this.tail.next = node;
}
this.tail = node;
this.length += 1;
}
pop() {
const popItem = this.head;
this.head = this.head.next;
this.length -= 1;
return popItem.item;
}
}
const input = require('fs')
.readFileSync('./dev/stdin')
.toString()
.trim()
.split('\n')
.map((v) => v.trim());
const [H, W] = input
.shift()
.split(' ')
.map((v) => Number(v));
let board = input.map((v) => v.split(''));
// 위, 아래, 왼쪽, 오른쪽
// 입력에서 주사위 탐색할 때 쓰일 값.
const bdx = [-4, 4, 0, 0];
const bdy = [0, 0, -4, 4];
// 입력으로부터 새로운 주사위를 만들 때 사용할 값.
// 위 /4 하면 되는데,,, 그냥 만들어 줬음.
const ddx = [-1, 1, 0, 0];
const ddy = [0, 0, -1, 1];
// 깨끗하게 비교에 사용될 수 있도록 정돈된 주사위의 전개도를 담을 배열
const tidyDice = [];
// 각 주사위 모눈에 인덱스를 부여함. Map<그림, 모눈인덱스>
/**
* ... xxx
* ... => 0 xxx => 511
* ... xxx
*/
const symbolIndex = new Map();
for (let i = 0; i < 1 << 9; i++) {
let x = i;
let shift = 0;
let symbol = '';
while (shift < 9) {
if ((x & (1 << shift)) != 0) {
symbol += 'x';
} else {
symbol += '.';
}
shift++;
}
symbolIndex.set(symbol, i);
}
// 인덱스를 회전했을 때 어떤 인덱스가 되는지 확인하기 위한 맵
const symbols = new Map();
symbolIndex.forEach((value, key) => {
const arr = [key.slice(0, 3).split(''), key.slice(3, 6).split(''), key.slice(6, 9).split('')];
const rotated = rotate(arr)
.map((v) => v.map((x) => x.join('')).join(''))
.map((s) => symbolIndex.get(s));
symbols.set(value, rotated);
});
/// 탐색가능한 주사위의 패턴 (11(정육면체 전개도 개수)*2(대칭) - (대칭해도 똑같은거) ) * 4(회전)
// 회전했을 때 원래 패턴이랑 같은 것도 있는데, 그 정도는 그냥 무시.
const dicePattern = [
////////////////////////0
[
[0, 1, 0, 0],
[1, 1, 1, 1],
[0, 1, 0, 0],
],
///////////////////////////1
[
[1, 0, 0, 0],
[1, 1, 1, 1],
[1, 0, 0, 0],
],
/////////////////////////// 2 3
[
[0, 1, 0, 0],
[1, 1, 1, 1],
[1, 0, 0, 0],
],
[
[1, 0, 0, 0],
[1, 1, 1, 1],
[0, 1, 0, 0],
],
///////////////////////////4 5
[
[0, 0, 1, 0],
[1, 1, 1, 1],
[1, 0, 0, 0],
],
[
[1, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 1, 0],
],
/////////////////////////// 6 7
[
[0, 0, 0, 1],
[1, 1, 1, 1],
[1, 0, 0, 0],
],
[
[1, 0, 0, 0],
[1, 1, 1, 1],
[0, 0, 0, 1],
],
/////////////////////////// 8 9
[
[0, 0, 1, 0],
[1, 1, 1, 1],
[0, 1, 0, 0],
],
[
[0, 1, 0, 0],
[1, 1, 1, 1],
[0, 0, 1, 0],
],
///////////////////////////10 11
[
[0, 0, 1, 1],
[0, 1, 1, 0],
[1, 1, 0, 0],
],
[
[1, 1, 0, 0],
[0, 1, 1, 0],
[0, 0, 1, 1],
],
/////////////////////////// 12 13
[
[0, 0, 1, 1],
[1, 1, 1, 0],
[1, 0, 0, 0],
],
[
[1, 0, 0, 0],
[1, 1, 1, 0],
[0, 0, 1, 1],
],
/////////////////////////// 14 15
[
[0, 1, 0, 0],
[0, 1, 1, 1],
[1, 1, 0, 0],
],
[
[1, 1, 0, 0],
[0, 1, 1, 1],
[0, 1, 0, 0],
],
/////////////////////////// 16 17
[
[0, 1, 0, 0],
[1, 1, 1, 0],
[0, 0, 1, 1],
],
[
[0, 0, 1, 1],
[1, 1, 1, 0],
[0, 1, 0, 0],
],
/////////////////////////// 18 19
[
[0, 0, 1, 1, 1],
[1, 1, 1, 0, 0],
],
[
[1, 1, 1, 0, 0],
[0, 0, 1, 1, 1],
],
].map((v) => rotate(v));
// 각 패턴을 전부 0 번 꼴로 만들어 줄꺼임.
// 5
// 1 2 3 4
// 6
//
const transformDice = [
(arr) => arr, //0
(arr) => {
//1
arr[0][1] = symbols.get(arr[0][0])[1];
arr[0][0] = -1;
arr[2][1] = symbols.get(arr[2][0])[3];
arr[2][0] = -1;
return arr;
},
(arr) => {
//2
arr[2][1] = symbols.get(arr[2][0])[3];
arr[2][0] = -1;
return arr;
},
(arr) => {
//3
arr[0][1] = symbols.get(arr[0][0])[1];
arr[0][0] = -1;
return arr;
},
(arr) => {
//4
arr[0][1] = symbols.get(arr[0][2])[3];
arr[0][2] = -1;
arr[2][1] = symbols.get(arr[2][0])[3];
arr[2][0] = -1;
return arr;
},
(arr) => {
//5
arr[0][1] = symbols.get(arr[0][0])[1];
arr[0][0] = -1;
arr[2][1] = symbols.get(arr[2][2])[1];
arr[2][2] = -1;
return arr;
},
(arr) => {
//6
arr[0][1] = symbols.get(arr[0][3])[2];
arr[0][3] = -1;
arr[2][1] = symbols.get(arr[2][0])[3];
arr[2][0] = -1;
return arr;
},
(arr) => {
//7
arr[0][1] = symbols.get(arr[0][0])[1];
arr[0][0] = -1;
arr[2][1] = symbols.get(arr[2][3])[2];
arr[2][3] = -1;
return arr;
},
(arr) => {
//8
arr[0][1] = symbols.get(arr[0][2])[3];
arr[0][2] = -1;
return arr;
},
(arr) => {
//9
arr[2][1] = symbols.get(arr[2][2])[1];
arr[2][2] = -1;
return arr;
},
(arr) => {
//10
arr[1][0] = symbols.get(arr[2][0])[1];
arr[2][0] = -1;
arr[0][1] = symbols.get(arr[0][2])[3];
arr[0][2] = -1;
arr[1][3] = symbols.get(arr[0][3])[1];
arr[0][3] = -1;
return arr;
},
(arr) => {
//11
arr[1][0] = symbols.get(arr[0][0])[3];
arr[0][0] = -1;
arr[2][1] = symbols.get(arr[2][2])[1];
arr[2][2] = -1;
arr[1][3] = symbols.get(arr[2][3])[3];
arr[2][3] = -1;
return arr;
},
(arr) => {
//12
arr[0][1] = symbols.get(arr[0][2])[3];
arr[0][2] = -1;
arr[1][3] = symbols.get(arr[0][3])[1];
arr[0][3] = -1;
arr[2][1] = symbols.get(arr[2][0])[3];
arr[2][0] = -1;
return arr;
},
(arr) => {
//13
arr[0][1] = symbols.get(arr[0][0])[1];
arr[0][0] = -1;
arr[2][1] = symbols.get(arr[2][2])[1];
arr[2][2] = -1;
arr[1][3] = symbols.get(arr[2][3])[3];
arr[2][3] = -1;
return arr;
},
(arr) => {
//14
arr[1][0] = symbols.get(arr[2][0])[1];
arr[2][0] = -1;
return arr;
},
(arr) => {
//15
arr[1][0] = symbols.get(arr[0][0])[3];
arr[0][0] = -1;
return arr;
},
(arr) => {
//16
arr[1][3] = symbols.get(arr[2][3])[3];
arr[2][3] = -1;
arr[2][1] = symbols.get(arr[2][2])[1];
arr[2][2] = -1;
return arr;
},
(arr) => {
//17
arr[1][3] = symbols.get(arr[0][3])[1];
arr[0][3] = -1;
arr[0][1] = symbols.get(arr[0][2])[3];
arr[0][2] = -1;
return arr;
},
(arr) => {
//18
const newArr = [
[-1, symbols.get(arr[1][0])[2], -1, -1],
[symbols.get(arr[1][1])[1], arr[0][2], arr[0][3], arr[0][4]],
[-1, arr[1][2], -1, -1],
];
return newArr;
},
(arr) => {
//19
const newArr = [
[-1, arr[0][2], -1, -1],
[symbols.get(arr[0][1])[3], arr[1][2], arr[1][3], arr[1][4]],
[-1, symbols.get(arr[0][0])[2], -1, -1],
];
return newArr;
},
];
// 시계방향으로 회전된 배열을 4개 반환하는 함수
function rotate(arr1) {
const r = arr1.length;
const c = arr1[0].length;
const arr2 = Array.from(Array(c), () => Array(r));
for (let i = 0; i < r; i++) {
for (let j = 0; j < c; j++) {
arr2[j][r - i - 1] = arr1[i][j];
}
}
const arr3 = Array.from(Array(r), () => Array(c));
for (let i = 0; i < r; i++) {
for (let j = 0; j < c; j++) {
arr3[r - i - 1][c - j - 1] = arr1[i][j];
}
}
const arr4 = Array.from(Array(c), () => Array(r));
for (let i = 0; i < r; i++) {
for (let j = 0; j < c; j++) {
arr4[c - j - 1][i] = arr1[i][j];
}
}
return [arr1, arr2, arr3, arr4];
}
// 주사위 그림에 따른 모눈인덱스를 찾아주는 함수
function getSymbol(i, j) {
let symbol = '';
symbol += board[i + 1][j + 1] + board[i + 1][j + 2] + board[i + 1][j + 3];
symbol += board[i + 2][j + 1] + board[i + 2][j + 2] + board[i + 2][j + 3];
symbol += board[i + 3][j + 1] + board[i + 3][j + 2] + board[i + 3][j + 3];
return symbol;
}
// 주사위 면이 맞는지 검사
function isDiceFace(i, j) {
return (
i >= 0 &&
j >= 0 &&
i + 4 < H &&
j + 4 < W &&
board[i][j] == '+' &&
board[i][j + 1] == '-' &&
board[i + 1][j] == '|' &&
board[i][j + 4] == '+' &&
board[i][j + 3] == '-' &&
board[i + 1][j + 4] == '|' &&
board[i + 4][j] == '+' &&
board[i + 4][j + 1] == '-' &&
board[i + 3][j] == '|' &&
board[i + 4][j + 4] == '+' &&
board[i + 4][j + 3] == '-' &&
board[i + 3][j + 4] == '|' &&
board[i + 1][j + 1] != 'o'
);
}
function checkPattern(pattern, dice) {
const r = pattern.length;
const c = pattern[0].length;
for (let i = 0; i < r; i++) {
for (let j = 0; j < c; j++) {
if ((pattern[i][j] == 1 && dice[i][j] == -1) || (pattern[i][j] == 0 && dice[i][j] >= 0))
return false;
}
}
return true;
}
function convertToFirstPattern(arr, cnt) {
while (cnt < 4) {
const r = arr.length;
const c = arr[0].length;
let rotatedArr = Array.from(Array(c), () => Array(r).fill(-1));
for (let i = 0; i < r; i++) {
for (let j = 0; j < c; j++) {
if (arr[i][j] > -1) rotatedArr[j][r - i - 1] = symbols.get(arr[i][j])[1];
}
}
arr = rotatedArr;
cnt++;
}
return arr;
}
// Main은
// 5
// 1 2 3 4
// 6 중에서 2의자리
//
// 다른 숫자도 2의 자리에 있는 형태로 만들어서 총 6개의 주사위 전개도를 반환
function changeMainFace(arr) {
const arr1 = arr;
const arr2 = [
[-1, symbols.get(arr[0][1])[1], -1, -1],
[arr[1][1], arr[1][2], arr[1][3], arr[1][0]],
[-1, symbols.get(arr[2][1])[3], -1, -1],
];
const arr3 = [
[-1, symbols.get(arr[0][1])[2], -1, -1],
[arr[1][2], arr[1][3], arr[1][0], arr[1][1]],
[-1, symbols.get(arr[2][1])[2], -1, -1],
];
const arr4 = [
[-1, symbols.get(arr[0][1])[3], -1, -1],
[arr[1][3], arr[1][0], arr[1][1], arr[1][2]],
[-1, symbols.get(arr[2][1])[1], -1, -1],
];
const arr5 = [
[-1, symbols.get(arr[1][3])[2], -1, -1],
[symbols.get(arr[1][0])[1], arr[0][1], symbols.get(arr[1][2])[3], symbols.get(arr[2][1])[2]],
[-1, arr[1][1], -1, -1],
];
const arr6 = [
[-1, arr[1][1], -1, -1],
[symbols.get(arr[1][0])[3], arr[2][1], symbols.get(arr[1][2])[1], symbols.get(arr[0][1])[2]],
[-1, symbols.get(arr[1][3])[2], -1, -1],
];
return [
...rotateMainFace(arr1),
...rotateMainFace(arr2),
...rotateMainFace(arr3),
...rotateMainFace(arr4),
...rotateMainFace(arr5),
...rotateMainFace(arr6),
];
}
// Main 기준으로 회전하는 함수 총 4개의 변형된 주사위 전개도를 반환
function rotateMainFace(arr) {
const arr1 = arr;
const arr2 = [
[-1, symbols.get(arr[1][2])[3], -1, -1],
[
symbols.get(arr[0][1])[3],
symbols.get(arr[1][1])[3],
symbols.get(arr[2][1])[3],
symbols.get(arr[1][3])[1],
],
[-1, symbols.get(arr[1][0])[3], -1, -1],
];
const arr3 = [
[-1, symbols.get(arr[2][1])[2], -1, -1],
[
symbols.get(arr[1][2])[2],
symbols.get(arr[1][1])[2],
symbols.get(arr[1][0])[2],
symbols.get(arr[1][3])[2],
],
[-1, symbols.get(arr[0][1])[2], -1, -1],
];
const arr4 = [
[-1, symbols.get(arr[1][0])[1], -1, -1],
[
symbols.get(arr[2][1])[1],
symbols.get(arr[1][1])[1],
symbols.get(arr[0][1])[1],
symbols.get(arr[1][3])[3],
],
[-1, symbols.get(arr[1][2])[1], -1, -1],
];
return [arr1, arr2, arr3, arr4];
}
const diceInfo = [];
for (let i = 0; i < H; i++) {
for (let j = 0; j < W; j++) {
if (isDiceFace(i, j)) {
let dice = Array.from(Array(9), () => Array(9).fill(-1));
dice[4][4] = symbolIndex.get(getSymbol(i, j));
board[i + 1][j + 1] = 'o';
const q = new Queue();
q.push([i, j, 4, 4]);
while (q.length > 0) {
const [boardX, boardY, diceX, diceY] = q.pop();
for (let k = 0; k < 4; k++) {
const nbx = boardX + bdx[k];
const nby = boardY + bdy[k];
const ndx = diceX + ddx[k];
const ndy = diceY + ddy[k];
if (isDiceFace(nbx, nby)) {
dice[ndx][ndy] = symbolIndex.get(getSymbol(nbx, nby));
board[nbx + 1][nby + 1] = 'o';
q.push([nbx, nby, ndx, ndy]);
}
}
}
while (dice.length > 0) {
let zero = true;
for (let k = 0; k < dice[0].length; k++) {
if (dice[0][k] >= 0) {
zero = false;
break;
}
}
if (zero) {
dice.shift();
} else {
break;
}
}
while (dice.length > 0) {
let zero = true;
for (let k = 0; k < dice[0].length; k++) {
if (dice[dice.length - 1][k] >= 0) {
zero = false;
break;
}
}
if (zero) {
dice.pop();
} else {
break;
}
}
while (true) {
let zero = true;
for (let i = 0; i < dice.length; i++) {
if (dice[i][0] >= 0) {
zero = false;
break;
}
}
if (zero) {
for (let i = 0; i < dice.length; i++) {
dice[i].shift();
}
} else {
break;
}
}
while (true) {
let zero = true;
for (let i = 0; i < dice.length; i++) {
if (dice[i][dice[i].length - 1] >= 0) {
zero = false;
break;
}
}
if (zero) {
for (let i = 0; i < dice.length; i++) {
dice[i].pop();
}
} else {
break;
}
}
let findPattern = false;
for (let i = 0; i < dicePattern.length; i++) {
if (findPattern) break;
for (let j = 0; j < 4; j++) {
const pattern = dicePattern[i][j];
const patternRow = pattern.length;
const patternColumn = pattern[0].length;
const diceRow = dice.length;
const diceCoulum = dice[0].length;
if (patternRow != diceRow || patternColumn != diceCoulum) continue;
if (checkPattern(pattern, dice)) {
diceInfo.push([i, j]);
tidyDice.push(
changeMainFace(transformDice[i](convertToFirstPattern(dice, j)))
.map((v) => {
let str = v[0][1].toString(2).padStart(9, '0');
str += v[1][0].toString(2).padStart(9, '0');
str += v[1][1].toString(2).padStart(9, '0');
str += v[1][2].toString(2).padStart(9, '0');
str += v[1][3].toString(2).padStart(9, '0');
str += v[2][1].toString(2).padStart(9, '0');
return str;
})
.sort()[0]
);
findPattern = true;
break;
}
}
}
}
}
}
const answerMap = new Map();
for (let i = 0; i < tidyDice.length; i++) {
if (answerMap.has(tidyDice[i])) {
const cnt = answerMap.get(tidyDice[i]);
answerMap.set(tidyDice[i], cnt + 1);
} else {
answerMap.set(tidyDice[i], 1);
}
}
const answer = [...answerMap]
.sort((a, b) => b[1] - a[1])
.map((v) => String(v[1]))
.join(' ');
console.log(answer);
728x90
'자료구조 알고리즘 > 백준' 카테고리의 다른 글
Node.js) 백준 26529번: Bunnies (0) | 2023.08.08 |
---|---|
Node.js) 백준 15841번: Virus Outbreak (0) | 2023.08.07 |
Node.js) 백준 1917번: 정육면체 전개도 (0) | 2023.08.05 |
Node.js) 백준 23289번: 온풍기 안녕! (0) | 2023.08.04 |
Node.js) 백준 8932번: 7종 경기 (0) | 2023.08.03 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 롱베케이션
- 서버개발
- create databases;
- BFS
- DB 생성
- 로드나인
- 서버점검
- node.js
- 동적프로그래밍
- 은둔청년체험
- 다이나믹프로그래밍
- create db
- 면접질문
- 투포인터
- 면접비
- 그래프
- 최소공통조상
- 투포인터 연습
- 다이나밍프로그래밍
- 개발자면접
- MySQL
- MOD
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
글 보관함