관리 메뉴

Mini

[틀림] 백준 17136 색종이 붙이기 // 구현, 원복 본문

Algorithm/back_tracking

[틀림] 백준 17136 색종이 붙이기 // 구현, 원복

Mini_96 2025. 3. 19. 00:42

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

* 풀이

  • dfs로 한칸씩 보면된다.
  • 요령은없다.
  • 구현은 추상화, 분리가 핵심..
  • 5개제한 -> 카운팅스타? 맵또는 배열

  • 가지치기
    • cnt가 ret보다 크다면, 해당 경로는 유망하지 않으므로 가지치기하면 더 최적화 가능
#include<bits/stdc++.h>
using namespace std; 

typedef long long ll;

int ret=987654321; //맵크기, 나무수, k년
int a[14][14];
int n=10;
map<int,int> m; //<색종이번호, 사용한횟수>

//좌표에 sz의 색종이를 놓을수 있는지
int check(int y, int x, int sz) {
   //범위쳌
   //n인경우는 dfs에서검사함 -> 제외
   if(y+sz>n || x+sz>n) return 0;
   for(int i=y;i<y+sz;++i) {
      for(int j=x;j<x+sz;++j) {
         if(a[i][j]==0) return 0; //금지칸이있다? 불가
      }
   }
   return 1;
}

// val 0 : 색종이로 칠한후 표시 -> 덮어쓰기 자동으로 불가체크 됨
// val 1 : 원복
void draw(int y, int x, int sz, int val) {
   for(int i=y;i<y+sz;++i) {
      for(int j=x;j<x+sz;++j) {
         a[i][j]=val;
      }
   }
}

//사용한 색종이 갯수
void dfs(int y, int x, int cnt) {
   //예외처리
   if(x==n) {
      dfs(y+1,0,cnt);
      return;
   }
   //모두 탐색완료
   if(y==n) {
      ret=min(ret,cnt);
      return;
   }
   // 현재 위치가 0이면(이미 색종이가 놓여있거나 원래 빈 칸, 금지칸) 다음 위치로 이동
   if(a[y][x]==0) {
      dfs(y,x+1,cnt);
      return;
   }

   for(int sz=5;sz>=1;sz--) {
      if(m[sz]==5) continue;

      if(check(y,x,sz)) {
         m[sz]++;
         draw(y,x,sz,0);
         dfs(y,x+sz,cnt+1);
         draw(y,x,sz,1); //원복
         m[sz]--;
      }
   }
   return;
}

int main(){
   ios_base::sync_with_stdio(0);
   cin.tie(0); cout.tie(0);
   
   for(int i=0;i<10;++i) {
      for(int j=0;j<10;++j) {
         cin>>a[i][j];
      }
   }

   dfs(0,0,0);

   if(ret==987654321) cout<<-1;
   else cout<<ret;
}