땅지원
땅지원's Personal blog
땅지원
전체 방문자
오늘
어제
  • 전체 (353)
    • Frontend (2)
      • React (2)
    • Backend (90)
      • Java (16)
      • Python (19)
      • Spring (23)
      • Database (21)
      • Troubleshooting (8)
    • DevOps (27)
      • ELK (13)
    • CS (40)
    • OS (2)
      • Linux (2)
    • Algorithm (95)
      • concept (18)
      • Algorithm Problem (77)
    • 인공지능 (25)
      • 인공지능 (12)
      • 연구노트 (13)
    • 수업정리 (35)
      • 임베디드 시스템 (10)
      • 데이터통신 (17)
      • Linux (8)
    • 한국정보통신학회 (5)
      • 학술대회 (4)
      • 논문지 (1)
    • 수상기록 (8)
      • 수상기록 (6)
      • 특허 (2)
    • 삼성 청년 SW 아카데미 (6)
    • 42seoul (12)
    • Toy project (3)
    • 땅's 낙서장 (2)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • 20.11.6 BB21플러스 온라인 학술대회
  • 20.10.30 한국정보통신학회 온라인 학술대회

인기 글

태그

  • ㅗ
  • I
  • D
  • E
  • 이것이 리눅스다 with Rocky Linux9

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
땅지원

땅지원's Personal blog

Algorithm/Algorithm Problem

백준 14722 우유도시(DP)

2022. 10. 24. 14:06
 

14722번: 우유 도시

영학이는 딸기우유, 초코우유, 바나나우유를 좋아한다. 입맛이 매우 까다로운 영학이는 자신만의 우유를 마시는 규칙이 있다.  맨 처음에는 딸기우유를 한 팩 마신다. 딸기우유를 한 팩 마신 후

www.acmicpc.net

더보기

BFS + dp table 이용(메모리초과)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;

/*
* 동,남쪽으로만 이동하기 때문에 전의 값을 계속 갱신해가면서 값을 더하는 dp문제 같음
*
* 딸기우유를 무조껀 처음에 먹어야한다고 하며 각 자리에 가면 먹거나 안먹거나 선택이 가능하니까
* 2가지 조건 나눠서 점화식 세우면 될 것 같은데??
*
* 1. bfs로 dp table 갱신하는 식으로 했는데 메모리초과
* 2. 그냥 단순 bfs로 했더니 (Queue에 우유 개수를 넘기는 식으로 그냥 가볼까?) 메모리초과
* 3. bfs를 사용하면 안되나?
* */

public class Main {
    static int N;
    static int[] dx = {0,1};
    static int[] dy = {1,0};
    static int[][] board, dp;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());

        board = new int[N][N];
        dp = new int[N][N];

        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < N; j++) {
                board[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        System.out.println(bfs()+1);
    }


    public static int bfs(){
        Queue<int[]> queue = new ArrayDeque<>();
        queue.add(new int[]{0,0});

        while(!queue.isEmpty()){
            int[] poll_data = queue.poll();
            int x = poll_data[0];
            int y = poll_data[1];
            for (int i = 0; i < 2; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                if(nx<0 || ny<0 || nx>=N || ny>=N)
                    continue;
                if (board[x][y] == 0 && board[nx][ny] == 1){
                    dp[nx][ny] = Math.max(dp[nx][ny], dp[x][y] + 1);
                    queue.add(new int[]{nx,ny});
                }
                else if(board[x][y] == 1 && board[nx][ny] == 2){
                    dp[nx][ny] = Math.max(dp[nx][ny], dp[x][y] + 1);
                    queue.add(new int[]{nx,ny});

                } else if (board[x][y] == 2 && board[nx][ny] == 0) {
                    dp[nx][ny] = Math.max(dp[nx][ny], dp[x][y] + 1);
                    queue.add(new int[]{nx,ny});
                }
                else{
                    dp[nx][ny] = dp[x][y];
                    queue.add(new int[]{nx,ny});
                }

            }
        }
        //System.out.println(Arrays.deepToString(dp));
        return dp[N-1][N-1];
    }

}

 

도저히 풀이 방법이 생각나서 카카시를 했다

 

느낀점은 dp table을 이용하는게 아직 매우 미숙하다는 것이다.

dp table을 세운다는건 알아도 역할을 확실하게 이해하고 있는지에 대해 회의감이 많이 느낀 문제다

 

Point는 총 3개이며

1. 딸기우유를 무조껀 처음 먹어야 한다

=> (0,0)에서 무조껀 딸기우유로 시작하는 경우는 아니기 때문에 조건을 나눠줘야 한다

=> 아예 새로운 -1값으로 현재 우유를 초기화 시켜준다음에 -1일 때 다음 먹어야하는 우유는 0이다 라는 식으로 나타낸다

 

2. dp table 이용

dp[x][y] = Math.max(dp[x][y], cnt);

if (cnt < dp[x][y])
    continue;

(x,y)로 아마 중복으로 검사가 들어올텐데 문제에서 최대한 많은 우유를 마셔야하니까 max로 골라줘야하고 이미 저장된 값보다 작은 값이 들어오면 검사할 필요가 없기 때문에 continue;

 

3.  가지치기

if(board[nx][ny] == nextMilk(now_milk) && dp[nx][ny] < cnt+1){
    dp[nx][ny] = cnt + 1;
    queue.add(new int[]{nx,ny,cnt+1,nextMilk(now_milk)});
}
queue.add(new int[]{nx,ny,cnt,now_milk});
dp[nx][ny] < cnt+1

이 코드를 빼면 메모리 초과 가 100% 난다.

똑같은 원리로 다음 마실 우유를 고르는데 nextMilk의 후보 중에서 dp의 값이 현재 Queue로 넘어온 cnt+1보다 작다면 이또한 고려할 필요가없는 문제다!

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;


public class Main_14722 {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());

        int[][] board = new int[N][N];
        int[][] dp = new int[N][N];
        Queue<int[]> queue = new ArrayDeque<>();

        int[] dx = {1,0};
        int[] dy = {0,1};


        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j < N; j++) {
                board[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        if (board[0][0] == 0){
            dp[0][0] = 1;
            queue.add(new int[]{0,0,1,0});
        }
        else{
            queue.add(new int[]{0,0,0,-1});
        }

        while(!queue.isEmpty()){
            int[] poll_data = queue.poll();
            int x = poll_data[0];
            int y = poll_data[1];
            int cnt = poll_data[2];
            int now_milk = poll_data[3];
            dp[x][y] = Math.max(dp[x][y], cnt);

            if (x==N-1 && y==N-1)
                continue;
            if (cnt < dp[x][y])
                continue;

            for (int i = 0; i < 2; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];
                if (nx<0 || ny<0 || nx>=N || ny>=N)
                    continue;
                if(board[nx][ny] == nextMilk(now_milk) && dp[nx][ny] < cnt+1){
                    dp[nx][ny] = cnt + 1;
                    queue.add(new int[]{nx,ny,cnt+1,nextMilk(now_milk)});
                }
                queue.add(new int[]{nx,ny,cnt,now_milk});
            }
        }

        System.out.println(dp[N-1][N-1]);




        }
        public static int nextMilk(int cur) {
            if(cur==-1) {
                return 0;
            } else if(cur==0) {
                return 1;
            } else if (cur==1) {
                return 2;
            } else {
                return 0;
            }
        }




    }

 

'Algorithm > Algorithm Problem' 카테고리의 다른 글

백준 7682 틱택토(구현)  (0) 2022.10.25
백준 1094 막대기(구현, 비트마스킹)  (0) 2022.10.24
백준 2931 가스관(구현, 시뮬레이션)  (0) 2022.10.24
백준 9376 탈옥 (다익스트라, 0-1 BFS) - 아직 푸는중...  (1) 2022.10.22
백준 2631 줄세우기(LIS, DP)  (1) 2022.10.18
    'Algorithm/Algorithm Problem' 카테고리의 다른 글
    • 백준 7682 틱택토(구현)
    • 백준 1094 막대기(구현, 비트마스킹)
    • 백준 2931 가스관(구현, 시뮬레이션)
    • 백준 9376 탈옥 (다익스트라, 0-1 BFS) - 아직 푸는중...
    땅지원
    땅지원
    신입 개발자의 우당탕탕 기술 블로그

    티스토리툴바