2월 28, 2024

[백준] 14226번 이모티콘 문제 BFS의 변형

1. 문제

1) 링크

www.acmicpc.net/problem/14226

2) 문제

영선이는 매우 기쁘기 때문에, 효빈이에게 스마일 이모티콘을 S개 보내려고 한다.

영선이는 이미 화면에 이모티콘 1개를 입력했다. 이제, 다음과 같은 3가지 연산만 사용해서 이모티콘을 S개 만들어 보려고 한다.

  1. 화면에 있는 이모티콘을 모두 복사해서 클립보드에 저장한다.
  2. 클립보드에 있는 모든 이모티콘을 화면에 붙여넣기 한다.
  3. 화면에 있는 이모티콘 중 하나를 삭제한다.

모든 연산은 1초가 걸린다. 또, 클립보드에 이모티콘을 복사하면 이전에 클립보드에 있던 내용은 덮어쓰기가 된다. 클립보드가 비어있는 상태에는 붙여넣기를 할 수 없으며, 일부만 클립보드에 복사할 수는 없다. 또한, 클립보드에 있는 이모티콘 중 일부를 삭제할 수 없다. 화면에 이모티콘을 붙여넣기 하면, 클립보드에 있는 이모티콘의 개수가 화면에 추가된다.

영선이가 S개의 이모티콘을 화면에 만드는데 걸리는 시간의 최솟값을 구하는 프로그램을 작성하시오.

3) 입력

첫째 줄에 S (2 ≤ S ≤ 1000) 가 주어진다.

4) 출력

첫째 줄에 이모티콘을 S개 만들기 위해 필요한 시간의 최솟값을 출력한다.

 

문제의 세부조건을 더 알아보기 위해서는 위의 링크에 들어가서 확인해보자.


 2. 풀이

이 문제는 중요한 변수가 크게 두 가지가 있다. 첫번째는 화면에 있는 이모티콘의 개수, 두번째는 클립보드에 있는 이모티콘의 개수이다. 할 수 있는 연산 또한 클립보드의 개수에 따라서 결과가 달라지기 때문에 이 문제는 화면이모티콘의 개수와 클립보드에 있는 이모티콘의 개수를 함께 queue에 넣어주어야 한다. while문을 돌때도 두 개를 함께 pop 해주어야 한다는 것을 알 수 있다. 

 

그렇다면, 할 수 있는 시행을 하나씩 보면서 화면이모티콘의 개수와 클립보드 이모티콘의 개수가 어떻게 변화하는지 알아보자

  1. 화면에 있는 이모티콘을 모두 복사해서 클립보드에 저장한다. : (화면, 클립) --> (화면, 화면)
  2. 클립보드에 있는 모든 이모티콘을 화면에 붙여넣기 한다.: (화면, 클립)--> (화면+클립, 클립)
  3. 화면에 있는 이모티콘 중 하나를 삭제한다. : (화면, 클립)--> (화면-1, 클립)

위와 같이 변한다는 것을 알 수 있다. 

시작은 화면이모티콘 1개와 클립보드 이모티콘 0개로 시작한다. 

따라서 queue 에 1과 0을 각각 push해준 채로 시작하면 된다.

 

그리고 가능한 3가지의 경우를 모두 다 queue로 처리해준다.

 while(!q.isEmpty()){
  int s=q.remove();
    int c=q.remove();
    if (time[s][s]==-1){ //첫번째 복사
   time[s][s]=time[s][c]+1;
  q.add(s);q.add(s);
            }
   if (s+c<=goal&&time[s+c][c]==-1){ //두번째 붙여넣기
     time[s+c][c]=time[s][c]+1;
     q.add(s+c); q.add(c);
            }
    if (s>=1 && time[s-1][c]==-1){ //세번째 삭제
  time[s-1][c]=time[s][c]+1;
q.add(s-1); q.add(c);
            }
        }

세가지를 모두 다 처리하면 위와 같다.

대부분의 bfs 문제는 한 가지 변수만 queue로 처리하지만 이 경우는 답이 두 가지 변수에 의해 영향을 받기 때문에 두 가지를 queue에 push, pop해준다는 점이 특이하다.

 

3. 코드 

전체 코드를 살펴보면 아래와 같다. 

import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int goal=sc.nextInt();
        int time[][]=new int[goal+1][goal+1]; // 화면이모티콘과 클립보드 이모티콘 개수 저장
        for(int i=0; i<=goal; i++){
            for(int j=0; j<=goal; j++){
                time[i][j]=-1; //처음 시간은 -1로 초기화
            }
        }
        Queue<Integer> q= new LinkedList<>();
        q.add(1);
        q.add(0);
        time[1][0]=0;
        while(!q.isEmpty()){
            int s=q.remove();
            int c=q.remove();
            if (time[s][s]==-1){
                time[s][s]=time[s][c]+1;
                q.add(s);q.add(s);
            }
            if (s+c<=goal&&time[s+c][c]==-1){
                time[s+c][c]=time[s][c]+1;
                q.add(s+c); q.add(c);
            }
            if (s>=1 && time[s-1][c]==-1){
                time[s-1][c]=time[s][c]+1;
                q.add(s-1); q.add(c);
            }
        }
        int ans=-1;
        for(int i=0; i<=goal; i++){
            if (time[goal][i]!=-1){
                if ((ans==-1)|| (ans> time[goal][i])){
                ans=time[goal][i];
            }
            }
            
        }
        System.out.println(ans);
    }
}