기본적인 DFS, 백트래킹 문제이다. DFS로 탐색하되 인접 칸이 모두 유효하지 않을 경우, 현재까지의 이동 칸 수를 가지고 최대 이동 칸 수를 갱신한 뒤 백트래킹으로 돌아간다. 원래 탐색 알고리즘에서는 노드의 방문처리가 필요한데, 이 문제에선 방문한 알파벳을 확인해야하므로 이를 통해 노드의 방문처리도 가능하다. 비트마스크를 이용하면 좀 더 최적화가 가능할 것 같긴하다.
처음에 큰 색종이부터 작은 색종이까지 좌상단부터 그리디 하게 붙이는 알고리즘을 사용해서 풀었는데, 틀렸습니다가 떴다. 생각해보니 큰 색종이부터 붙인다고 최적해가 찾아지는 것은 아니었다. 종이의 크기가 10*10으로 작았기 때문에 브루트 포스와 백트래킹으로 모든 경우를 탐색하기로 했다.
전체 종이의 좌상단에서부터 1이 처음 등장하는 곳을 찾고 그 곳에 크기별 색종이를 붙일 수 있는지 확인한 후, 붙일 수 있다면 붙인다. 그 다음 또 1이 처음 등장하는 곳을 찾아 크기별 색종이를 붙일 수 있는지 확인한 후 붙이는 것을 반복한다. 만약 더 이상 1이 등장하는 곳이 없다면 종이를 다 채운 것이므로 최소 색종이 수를 갱신하고, 탐색 과정에서 최소 색종이 수보다 더 많은 종이를 사용중이라면 백트래킹으로 돌아간다. 물론, 남은 1이 존재하지만 붙이려고 하는 크기의 색종이를 모두 소모한 경우나 해당 색종이를 붙일만큼 공간이 나지 않는 경우는 더 탐색하지 않는다.
위와 같은 흐름으로 알고리즘을 작성했고, 이제 색종이를 붙이는 모든 경우를 따질 수 있게 되어 통과했다. 어떻게 하면 색종이를 붙이는 모든 경우를 효율적으로 따져볼 수 있을까를 떠올리는 것이 까다로운 문제였다. 크기 별로 붙일 수 있는 케이스를 모두 배열에 저장해놓고, 하나하나 선택된 케이스와 선택되지 않은 케이스로 나누어 계산해볼까도 생각했다. 그러면 아마 워스트 케이스가 종이의 모든 칸이 1일 경우일 것인데, 연산횟수를 어림잡다가 바로 포기했다..
#include<iostream>
usingnamespacestd;
intpaper[10][10] = {0,};
intcolorPaper[6] = {0, 5, 5, 5, 5, 5};
intnextY=0, nextX=0;
intminColorPaper = 26;
voidfill(inty, intx, intsize, intnum) {
for(inti=y; i<y+size; i++) {
for(intj=x; j<x+size; j++) {
paper[i][j] = num;
}
}
}
boolcanFill(inty, intx, intsize) {
if(y+size>10 || x+size>10) {
returnfalse;
}
for(inti=y; i<y+size; i++) {
for(intj=x; j<x+size; j++) {
if(paper[i][j]==0) {
returnfalse;
}
}
}
returntrue;
}
voidfindNext(inty, intx) {
for(inti=y; i<10; i++) {
for(intj=0; j<10; j++) {
if(paper[i][j]==1) {
nextY = i;
nextX = j;
return;
}
}
}
nextY = -1;
nextX = -1;
return;
}
voidDFS(inty, intx, intcnt) {
if(minColorPaper<=cnt) {
return;
}
findNext(y, x);
if(nextX==-1&&nextY==-1) {
minColorPaper = cnt;
return;
}
intnY = nextY;
intnX = nextX;
for(intk=5; k>=1; k--) {
if(colorPaper[k] == 0) continue;
if(!canFill(nY, nX, k)) continue;
colorPaper[k]--;
fill(nY, nX, k, 0);
DFS(nY, nX, cnt+1);
fill(nY, nX, k, 1);
colorPaper[k]++;
}
}
intmain() {
for(inti=0; i<10; i++) {
for(intj=0; j<10; j++) {
cin>>paper[i][j];
}
}
DFS(0, 0, 0);
if(minColorPaper==26) {
cout<<"-1";
return0;
}
cout<<minColorPaper;
return0;
}
2. 데일리 미션 - 앱개발 용어 정리
-IDE: 통합 개발 환경, 소프트웨어 개발을 위한 모든 작업을 하나의 프로그램 안에서 처리할 수 있도록 처리한 것.
-컨벤션(코딩 컨벤션): 약속된 코딩 스타일, 규칙. 다수의 인원이 개발하는 프로젝트라면, 가독성 및 유지보수를 위해 필수적.
-자료형: 데이터의 형식을 식별할 수 있게 하는 분류. 이를 통해 메모리 상에서 비트의 나열인 데이터를 구분하여 처리할 수 있다.
-변수와 상수: 변수는 런타임 중에 변경될 수 있으며, 상수는 변경될 수 없다. 일반적으로 상수는 메모리의 Code 영역에 로드되어 Read-Only로 동작하게 된다.
-메소드: 클래스 내에서 기능을 함수형태로 구현해놓은 부분.
-클래스: 특정 속성 값들을 보유하고, 특정한 기능을 하는 인스턴스를 생성하기 위해 정형화 해놓은 틀.