Per ardua ad astra !
I'm On My Way
Per ardua ad astra !
전체 방문자
오늘
어제
  • 분류 전체보기 (126)
    • Algorithm (50)
      • 백준 (30)
      • SWEA (3)
      • JUNGOL (3)
      • Programmers (5)
      • LeetCode (2)
    • 안드로이드 개발 (6)
      • Java로 개발 (0)
      • Kotlin으로 개발 (3)
    • Spring (41)
      • Spring기본 (17)
      • JPA기본 (15)
      • JPA활용 SpringBoot 기본 (9)
      • API 개발 기본 (0)
    • 네트워크 (3)
    • 운영체제 (0)
    • Life (3)
      • 책 (0)
      • 자기계발 (1)
      • 일상 (2)
    • 노마드코더 (3)
      • python으로 웹 스크래퍼 만들기 (3)
    • 프로그래밍 언어 (17)
      • Java 기본 (2)
      • 코틀린 기본 (15)

블로그 메뉴

  • 홈
  • 방명록

인기 글

hELLO · Designed By 정상우.
Per ardua ad astra !

I'm On My Way

Algorithm/백준

[Java] BaekJoon 2758. 로또(골드4) (DFS, DP)

2021. 10. 4. 11:23

문제출처: https://www.acmicpc.net/problem/2758

 

2758번: 로또

선영이는 매주 엄청난 돈을 로또에 투자한다. 선영이가 하는 로또는 1부터 m까지 숫자 중에 n개의 수를 고르는 로또이다. 이렇게 열심히 로또를 하는데, 아직까지 한 번도 당첨되지 않은 이유는

www.acmicpc.net

 

문제이해

 

목표

더보기
로또를 산다.
로또를 살 때 고르는 숫자는 N개, 그리고 숫자의 범위는 1부터 M까지다. 
각 숫자는 이전에 고른 수보다 적어도 2배가 되도록 고른다.
N,M과 주어질 때, 로또를 고르는 방법의 수 만큼 로또를 구매한다.
선양이가 구매하는 로또의 개수를 출력하라

 

풀이

 

첫번째 고안한 풀이 

 

1. 주어진 M을 N만큼 2로 나눠서 각자릿수의 상한 값을 정해준다. 

  ex) N = 4, M = 10 일때 

   ArrayList => 10, 5, 2 ,1이 담긴다. 

  • 끝 인덱스의 값(1)부터, 로또의 첫번째 자리는 1이하여야 되고
  • 로또의 두번째 자리는 2이하여야 되고
  • 로또의 세번째 자리는 5이하여야 되고
  • 로또의 네번째 자리는 10이하여야 된다.

이렇게 상한 값을 정하고

 

2.  첫번째 자릿수부터 DFS로 들어가서 구할 수 있는 로또 방법을 구한다. 

이때, DP를 이용하는데,
DP[들어온 자릿수][들어온 값]을 기억하여, 이미 있는 값이면 이를 활용하고 아니면 탐색할 수 있도록 한다. 

 

 

다른 사람의 코드를 본 풀이

 

  1. dp를 이용하여 문제를 푼다.
    dp[자릿수][값] => 해당 자릿수에 1부터 해당 값까지의 수로 발생할 수 있는 로또 경우의 수를 의미한다.

  2. 점화식이 있다. 
    dp[i][j] = dp[i-1][j/2] + dp[i][j-1];
     
  3. [현재 자릿수][현재 번호] = [이전자릿수][현재번호/2] + [현재자릿수][현재번호-1]

    ex)
    dp[4][16] = dp[3][8] + dp[4][15]
    dp[3][8] = dp[2][4] + dp[3][7]
    dp[2][4] = dp[1][2] + dp[2][3]
    dp[1][2] = dp[0][1] + dp[1][1]
    dp[0][1] = 1
  4. 예시
    dp[1][1] = dp[0][0] + dp[1][0] = 1
    dp[1][2] = dp[0][1] + dp[1][1] = 2
    dp[1][3] = dp[0][1] + dp[1][2] = 3
    dp[1][4] = dp[0][2] + dp[1][3] = 4
    .
    .
    .
    dp[2][1] = dp[1][0] + dp[2][0] = 0
    dp[2][2] = dp[1][1] + dp[2][1] = 1
    dp[2][3] = dp[1][1] + dp[2][2] = 2
    dp[2][4] = dp[1][2] + dp[2][3] = 4
    .
    .
    .

2번째코드는 WOOSERK님의 문제풀이를 보고 이해했습니다. 

소스코드

첫번째 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import static java.lang.System.in;

public class 로또 {
    private static int N;
    private static int M;
    private static long answer;
    private static long[][] dp;
    private static ArrayList<Integer> arrayList;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        int T = Integer.parseInt(br.readLine());
        String[] strArr;
        StringBuilder sb = new StringBuilder();
        for (int t = 0; t < T; t++) {
            arrayList = new ArrayList<>();
            answer = 0;
            strArr = br.readLine().split(" ");
            N = Integer.parseInt(strArr[0]);
            M = Integer.parseInt(strArr[1]);
            dp = new long[N][M + 1];

            // 범위
            int m = M;
            arrayList.add(M);
            for (int i = 0; i < N - 1; i++) {
                m /= 2;
                arrayList.add(m);
            }


            // 정답 도출
            for (int i = 1; i <= arrayList.get(N - 1); i++) {
                answer += get(i, N - 1);
            }
            sb.append(answer + "\n");
        }
        System.out.println(sb);
    }

    private static long get(int num, int restCount) {
        if (restCount == 0) {
            return 1;
        }

        int next = num * 2;
        long sum = 0;
        for (int i = next; i <= arrayList.get(restCount - 1); i++) {
            if (dp[restCount][i] == 0) {
                dp[restCount][i] = get(i, restCount - 1);
            } else{
            }
            sum += dp[restCount][i];
        }

        return sum;
    }

}

 

두번째 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class 로또 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // dp 알고리즘
        long[][] dp = new long[11][2001];
        for (int i = 0; i <= 2000; i++) { // 초기화
            dp[0][i] = 1;
        }

        for (int i = 1; i <= 10 ; i++) { // 자릿수
            for (int j = 1; j <= 2000 ; j++) { // 값
                dp[i][j] = dp[i - 1][j / 2] + dp[i][j - 1];
            }
        }

        // 정달 출력
        int T = Integer.parseInt(br.readLine());
        StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        for (int t = 0; t < T; t++) {
            st = new StringTokenizer(br.readLine());
            int N = Integer.parseInt(st.nextToken());
            int M = Integer.parseInt(st.nextToken());
            sb.append(dp[N][M]).append("\n");
        }
        System.out.println(sb);
    }
}

 

    'Algorithm/백준' 카테고리의 다른 글
    • [Java] BaekJoon 2800. 괄호 제거(골드5) (부분집합) (DFS)
    • [Java] BaekJoon 2661. 좋은수열(골드4) (DFS) (백트래킹)
    • [Java] BaekJoon 14938. 서강그라운드 (골드4) (Dijkstra)
    • [Java] BaekJoon 1719. 택배(골드4) (dijkstra)
    Per ardua ad astra !
    Per ardua ad astra !
    개발자 지망생이며 열심히 공부하고 기억하기 위한 블로그입니다.

    티스토리툴바