문제보기


문제를 살펴보면 이러하다.


1. 한번에 1~2계단 갈 수 있다. 

2. 연속3개는 밟을 수 없다. 

3. 그리고 밟았을때, 포도주 문제와 달리 선택/미선택의 결정을 할 수 없다. 


경우를 나눠보자 


첫 번째, 1개 연속 밟았을 경우 

i 번째 일때 , i-1을 밟지 못한다. 그리고 i-2번째를 밟고 올라온다 

-- > D[i-2]+A[i]


두 번째, 2개 연속 밟았을 경우 

i번째 일때, i-1을 밟아야한다. 하지만 i-2번을 밟으면 규칙에 위배되므로 밟지 않는다. 

그리고 D[i-3]을 더한다.(여기는 뭘해도 상관없다. 규칙에 영향을 안받음)


점화식은 아래와 같다. 

 dp[i] = Math.max(dp[i-2]+arr[i], dp[i-3]+arr[i-1]+arr[i]);

2차원 배열의 경우 점화식 : D[i][1] = Math.max(D[i-2][2],D[i-2][1])+A[i]

D[i][2] = D[i-1][1] + A[i]

Math.max(D[N][1],D[N][2])

<전체코드>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package Problems;
/**
 * 
 * 백준 2579 계단오르기 
 * 
 * 동적계획법 
 * 
 * 
 */
import java.util.Scanner;
public class Boj2579dp {
    public static int n,arr[],dp[];
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        n = in.nextInt();
        arr = new int[n+1];
        dp = new int[n+1];
        
        for(int i = 1; i <=n; i++) {
            
            arr[i] = in.nextInt();
        }
        
        dp[1= arr[1];
        dp[2= arr[1+ arr[2];
        for(int i = 3; i <=n; i++) {
            
            dp[i] = Math.max(dp[i-2]+arr[i], dp[i-3]+arr[i-1]+arr[i]);
            
        }
        
        System.out.println(dp[n]);
    }
}
 
cs


* 다시 풀어볼 : 파티 
* (26)추가 리스트 : 1916(Boj1916dij2) , 9465(Boj9464), 1261(Boj1261dp2) 
* (27)추가 리스트 : 1904(Boj1904dp2), 2139(Boj2139dp) ,2638(Boj2638dfs2)
* (28)추가 리스트 : 7576(Boj7576bfs2), 11403(Boj11403floyd2)
* (29)추가 리스트 : 2665(Boj2665dij)
* (29)추가 리스트 : 2156(Boj2156dp2), 1915(Boj1915dp2)
* <11월> 
* (01)추가 리스트 : 11051(Boj11051dp),2362(Boj2362dp2),1012(Boj1012dfs2)
* (02)추가 리스트 : 1699(Boj1699dp2), 1238(Boj1238dij2)
* (03)추가 리스트 : 9095, 1463, 11726, 11727

2017.11.03 ** 금요일 ** Solution - 1463(1로만들기)

풀이방법: 동적계획법

DP를 풀 수 있다면 쉬운문데 ,

우리는 1로 만들것이고

문제에서는 이미 3개의 케이스를 줬다.

N의 케이스를 나눠보자

3으로 나누면 N의 상태는 N/3이된다.

2로 나누면 N/2

1을 빼면 N-1

이렇게 3개를 나눠서 최소값을 찾으면 되는 문제이다.

점화식 :

dp[1] = 0;

        for(int i = 2; i < N+1; i++) {

            dp[i] = dp[i-1] + 1;

            if(i%3==0&&dp[i] > dp[i/3]+1) {
                dp[i] = dp[i/3] + 1;
            }

            if(i%2==0&&dp[i]>dp[i/2]+1) {
                dp[i] = dp[i/2] + 1;
            }


        }

—————————————————————————————————————

* 다시 풀어볼 : 파티 
* (26)추가 리스트 : 1916(Boj1916dij2) , 9465(Boj9464), 1261(Boj1261dp2) 
* (27)추가 리스트 : 1904(Boj1904dp2), 2139(Boj2139dp) ,2638(Boj2638dfs2)
* (28)추가 리스트 : 7576(Boj7576bfs2), 11403(Boj11403floyd2)
* (29)추가 리스트 : 2665(Boj2665dij)
* (29)추가 리스트 : 2156(Boj2156dp2), 1915(Boj1915dp2)
* <11월> 
* (01)추가 리스트 : 11051(Boj11051dp),2362(Boj2362dp2),1012(Boj1012dfs2)
* (02)추가 리스트 : 1699(Boj1699dp2), 1238(Boj1238dij2)
* (03)추가 리스트 : 9095, 1463, 11726, 11727

2017.11.03 ** 금요일 ** Solution - 11726,11727 (2Xn타일링,2)

풀이방법: 동적계획법


개인적으로 처음에 해맷다 , 일단 그리는게 너무 싫다..

돌리고 돌리고, 이상한 그림도 나오고..

마음잡고 다시 풀었을때

추가되는 것에 집중해봤다.

예제로 2x4까지 그리면 충분히 규칙을 찾을 수 있다.


타일의 종류는 2개가 있다.

그리고 이것을 마지막에 배치할때 두 가지 방법이 있다.

마지막에 일단 배치시켜보자

앞에는 2x(N-1) , 2x(N-2) 구역만 챙기면 된다.

즉, n-1 번째에는 1x2가 하나씩 더 붙는거고

n-2번째에는 2*1이 두개가 붙는다.


끝이다.

    dp[0] = 1;
        dp[1] = 1;

        for(int i = 2; i < n+1; i++) {

        dp[i] = dp[i-1] + dp[i-2];
        dp[i] %= 10007;

        }


—————————————————————————————————————


'알고리즘(추가예정) > 동적계획법' 카테고리의 다른 글

백준 2579 계단오르기  (0) 2017.11.07
백준 1463 1로 만들기  (0) 2017.11.03
백준 1699 제곱수의 합  (0) 2017.11.02
백준 11051 이항 계수2  (0) 2017.11.01
백준 1915 가장 큰 정사각형  (0) 2017.11.01

2017.11.02 ** 목요일 ** Solution - 1699(제곱수의 합)
백준 1699 제곱수의합

풀이방법: 동적계획법

엄청 시간이 걸렸던 문제다.

처음에 생각했던 것은 d[2-1] = d[1]+1.. 이런식으로 했었다.

그런데 여기서 4=2의 제곱이 되니 카운트가 바껴야 하는데 그 포인트를 못구했다.

그래서 중간에 월드시리즈 7차전을 잠깐보고 다시 문제를 풀었다.

오늘따라 다저스 타자들이 힘이 없어 보였다..나처럼 ㅜ

풀이방식

한번 생각해보자 ,

처음에 생각했던 방식 d[N - (N-1)] = d[N-1]+1 에 대해서 한번더 생각해보았다.

이렇게 하다보면 d[4]일때가 1차적으로 문제가 생기는데 ,

d[4-4] = d[0]+1을 만들어 줘야하기 때문이다.

자세히 식을 들여다보니 4 =2*2 가 된다. 그렇다면 1은 1x1이 된다는 것을 알 수 있다.

이제 반복문에 대해서 생각을 해보았다.

먼저 우리는 동적계획법을 할꺼고 bottom-up 방식을 사용하기 때문에 1부터 n까지 계산을

해줘야 된다.

for(int i = 1; i < n+1; i++) 로 시작하여

for(int j = 1l; j*j<i; j++)를 만든다. jxj < i 가 포인트인데 이유는

이렇게 하면 2의 제곱은 4부터 등장하게 되고, 처음 방식을 하면서 문제였었던 8은

d[8-4] = d[4] +1 = d[0] +1 +1 = 2가 될 수 있다.

따라서 조건에 의해 제곱수의 범위를 잘 나눌 수 있다. (손으로 해보는 것을 추천한다.)

점화식은 간단하다.

d[i] = Math.min(d[i],d[i-j*j]+1)

여기서 답을 놓칠뻔했다.

왜냐하면 d[i]를 초기화 해주지 않았다. d[i]의 초기화는 모두 d[i]=i로 해야된다.

이유는 모든 수는 1의 제곱으로 구성되어있기때문에, 1의 개수가 최대 개수가 된다.
코드 전체 보기

: 알고리즘은 항상 어렵다.

2017.11.01 ** 수요일 ** Solution - 11051(이항 계수2)
백준 11051 이항 계수2

풀이방법: 동적계획법


문제 해석

이항 계수 문제이다. 고등학교때 수학을 배웠다면, 쉽게 생각할 수 있다.

단 .. 기억을 하고있다면 ...

역시 나는 기억하지 못하고 있었다(공부는 못해도 수학은 좀 했다 신승범짱!)

네이버 검색을 해서 이항계수의 공식을 보는데 이렇게 풀면 되겠구나 하는게 있었다.


출처 : https://ko.wikipedia.org/wiki/%EC%9D%B4%ED%95%AD_%EA%B3%84%EC%88%98


이 공식을 보고 풀이를 시작했다.

풀이방식

한번 생각해보자 ,
우리는 n과 k를 안다.
두가지로 나눠져있다.

=> 두개의 경우로 나눠서 합치자!

순열,조합을 풀다보면 항상 재귀를 떠올리게 된다.

이것 또한 재귀적 방법으로 풀면된다. 또한 메모이제이션을 통해 효율성을 높여주면된다.

그리고 공식에서는 우측이 n+1이지만, 우리는 굳이 저렇게 할필요없다. 모든 항목을 -1해주자

이제 끝이다. 뽑기만 하면된다.

그리고 베이스 케이스 설계를 해야되는데, 한 번 생각을 해보자, 뽑을때마다 각 케이스 별로 -1씩을 해줄것이다.

dp {n}[k} = solution(n-1,k-1) + solution(n-1,k);

이렇게 식을 세우게 되면 어느순간 k==n 또는 k==0이된다. 수학시간에 배웠다. nCn =1 , nC0 = 1이다.

그러면 우리는 베이스 케이스를 설계 할 수 있다.

if(n==k||k==0) return 1;

이렇게 설계하면 될 것이다.

그리고 메모이제이션

if(dp{n}{k}>0) return dp{n}{k}

이제 끝이다 !

이렇게 3줄이면 끝난다. 검증을 하고 싶다면 예제를 손으로 하면된다. 5분도 안걸린다.
코드 전체 보기

: 나이를 먹더니 수학을 다 까먹은 것 같다..

2017.10.31 ** 화요일 ** Solution - 1915(가장 큰 정사각형)

풀이방법: 동적계획법



문제 해석

기억난다.. 처음 풀었던 당시에 엄청 끙끙..거렸다는 것을..
알고보면 상당히 쉬운 문제이나 , 당시에 그 아이디어까지 가는데
머리가 좋지 않아서 2시간정도 걸렸던것 같다..

그 당시 풀이보다 시간복잡도가 반이나 줄어서 이렇게 포스팅하게 되었다.
(더 익숙해졌길래 의아했는데 , 알고보니 카카오 모의테스트 였구나..)



풀이방식

처음 이 문제를 접했을때는, 무식하게 완탐하려고했다.. 그렇게 시간이 흐르고 흘러

코드를 보니 엄청 더럽고, 내가 잘못하고 있다는 것을 알게되어 생각을 더하게 되었다.

문제를 잘보면 직관적으로 1로 이루어진 4각형이 보인다. 우리는 저 크기를 골라 내야한다.

처음에 시도했던 방법은 왼쪽위의 끝점(0,0)부터 계산해야하나 했다. 그런데 그렇게 하다보면

어떻게 사각형을 판별해야하는지 의문이 생긴다.

그래서 그 다음으로는 매핑되는 점을 선택해서 돌려보았다. 뭔가 사각형으로 마지막점까지 갈 수가 있어졌다.

그렇다면 어떻게 계산을 할지 고민해보았다. 예제에 있는 사각형을 보고 좀 전에 사각형 판별법과 같이 생각해보면

판별되는 숫자를 1로 감싸고 있다. ?!-> 아 변이 2다 ..그렇다면 1은 변이 1로 생각할 수 있겠다!




그렇다면 판별되는 숫자를 2로 바꿔주면 2가 될것같다.

다시 해석해보자면 판별되는 숫자를 기준으로 그 숫자와 나머지 3개가 같으면 +1로 증가시켜준다(정사각형이기때문에!)

하지만 잘생각해보면 0에서 -> 1도 만들어야하고 , 각각 한칸당 넓이가 1인 정사각형이다.

그래서 3개의 공간 ( 왼쪽위 , 바로위 , 왼쪽)을 비교해서 가장 작은 수를 +1시킨다.(그래야 주위에 0이 잇을때 1인 정사각형을 만듬)
->map[i][j] = Math.min(map[i - 1][j - 1], Math.min(map[i - 1][j], map[i][j - 1])) + 1;

그렇게 판별되는 정사각형의 넓이를 계산하여 최대 사각형의 넓이 변수 (maxCnt)와 비교하여 마지막에 출력한다.
->maxCnt = maxCnt < map[i][j] ? map[i][j] : maxCnt;

: 좀 마지막에 시간이 걸렸다.. 오류가 계속났다. 왜 그런지살펴보니 maxCnt*maxCnt가 답인데, 그냥 maxCnt만 출력했다..주의하자..





+ Recent posts