일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- CSS
- 프로그래머스코테
- 알고리즘
- 자바스크립트
- 프로그래머스JS
- 안드로이드 스튜디오
- JS프로그래머스
- js코테
- 익스프레스
- 포이마웹
- 코딩테스트
- HTML
- dp알고리즘
- css기초
- 리액트댓글기능
- 프로그래머스
- 다이나믹프로그래밍
- 백준
- 리액트커뮤니티
- 백준구현문제
- 백준nodejs
- 백준구현
- 코테
- 백준js
- 리액트
- HTML5
- 백준골드
- 몽고DB
- 백준알고리즘
- JS
- Today
- Total
개발새발 로그
다이나믹 프로그래밍 (Dynamic Programming) - 타일링문제 2 본문
https://www.acmicpc.net/problem/2133
3×N 크기의 벽을 2×1, 1×2 크기의 타일로 채우는 경우의 수를 구해보자.
입력
첫째 줄에 N(1 ≤ N ≤ 30)이 주어진다.
출력
첫째 줄에 경우의 수를 출력한다.
아래 그림은 3×12 벽을 타일로 채운 예시이다.
이전 문제와 똑같이 생각하면된다.
1칸을 뺐을 때와 2칸을 뺐을 때를 일단 구해본다.
그럼 위와같이 n-1일 때는 0가지, n-2일 때는 3가지가 나온다.
그러면 D[2] = 3 * D[n-2] 라는 식이 나온다.
->하지만 이 식은 정답이 아니다.
한번 3칸이 뺐을 경우를 계산 해보자. -> 3칸일 때는 1 x 2 막대로 만들 수 있는 경우의 수가 나오지 않는다.
그럼 4칸을 뺐을 경우를 게산해보자 -> 4칸일 때는 4칸을 뺐을 때만 나오는 경우의 수 2가지가 나오게된다.(기존의 경우 추가)
또한 6칸을 뺐을 경우 -> 6칸을 뺐을 때만 나오는 경우의 수 2가지가 나온다.
D[n] = 3 * D[n-2] + ( 2 * D[n - 4] +
2 * D[n- 6] +
. .
. .
2 * D[0] )
이러한 식이 나오게 된다.
이 식을 코드로 바꿔보자.
let fs = require('fs');
let input = fs.readFileSync('/dev/stdin').toString().split(' ');
let N = Number(input);
var d = Array.from({length:1001},()=>0);
function DP(x){
// 0일 때를 하는 이유는 d[0]일 때가 아래 식에서 나올 가능성이 있으므로
if(x == 0) return 1;
if(x == 1) return 0;
if(x == 2) return 3;
if(d[x] != 0) return d[x];
//만약 2칸만 뺐을 때는 3가지가 나오니까 처음 식인 3* DP(x-2)를 해준다.
var result = 3 * DP(x-2);
for(var i = 3; i <= x; i++){
if(i % 2 == 0){ //짝수일 때 2가지가 추가되니까 2를 곱한 값을 계속 더해준다.
result += 2 * DP(x - i); //여기서 만약 x가 4면 4-4로 0이 나오는 구간이 있다.
}
}
return d[x]=result;
}
console.log(DP(N));
x===0 일 때를 추가한 이유는 원래 0일 때는 이전 문제에서도 있어야했다.
이 문제에서는 DP[0]이라는 값이 나오기때문에 추가해줘야한다. -> 급수처럼 초항이 중요할 때는 꼭 필요
쉽게말해서 DP[4]가 들어가면 3*DP(2) ->3*3*DP[0] -> 3 * 3 * 1 이 var result = 3 * DP(x-2)에서 나온다.
근데 우리는 여기서 끝내면 안된다. 4에서 6에서 ... 특별한 경우의 수가 생기므로 더해줘야한다.
아래 for문에서 3 , 4가반복된다. 3일때는 그냥넘어가고
4일 떄 result+=2*DP(4-4)가 실행된다. 즉 x==0일 때 1을 넣어야 DP[4]일때의 2가지의 경우를 더해줄 수 있다.
D[n] = 3 * D[n-2] + ( 2 * D[n - 4] +
2 * D[n- 6] +
. .
. .
2 * D[0] ) -> 이 식이 코드로 바뀐 모습이다.
https://www.acmicpc.net/problem/14852
2×N 크기의 벽을 2×1, 1×2, 1×1 크기의 타일로 채우는 경우의 수를 구해보자.
입력
첫째 줄에 N(1 ≤ N ≤ 1,000,000)이 주어진다.
출력
첫째 줄에 경우의 수를 1,000,000,007로 나눈 나머지를 출력한다.
타일의 종류가 총 3개다.
그러면 이전에 배웠던 것처럼 1칸을 뺐을 때와 2칸을 뺐을 때를 구해보자
그럼 D[n] = 3 * D[n-2] + 2 *D[n-1] 라는 식이 나오게 된다.
하지만 위 문제처럼 또다른 방식이 나오게된다.
4칸을 뺐을 때 위와같이 분할되지않는 2가지가 나오게 된다.
5칸을 뺐을 때도 위와같이 분활되지않는 2가지가 추가된다.
즉 1칸씩 증가할 때마다 2가지가 추가되게 된다.
D[n] = 2 * D[n - 1] + 3 * D[n - 2] + ( 2 * D[n - 3] +
2 * D[n - 4] +
. .
. .
2 * D[0] ) -> 이런 식이 나오게 된다.
let fs = require('fs');
let input = fs.readFileSync('/dev/stdin').toString().split(' ');
let N = Number(input);
var d = Array.from({length:1000000},()=>0)
function DP(x){
if(x==0) return 1;
if(x==1) return 2;
if(x==2) return 7;
if(d[x]!=0) return d[x];
var result=3*DP(x-2)+2*DP(x-1);
for(var i=3;i<=x;i++){
result+=(2*DP(x-i))%100000007
}
return d[x]=result%100000007
}
console.log(DP(N));
하지만 이 경우에는 시간초과가 나오게 된다. ->DP의 호출이 많아짐
4칸 뼀을 때 5칸 뺐을떄...의 식 2 * DP(x - i) : 이 식의 경우 또한 이전의 경우의 수에서 2씩 경우의 수가 추가되어 2를 곱해주는 거니까
사실 당연히 메모제이션의 개념을 사용할 수 있다. -> 시간 단축 가능
그래서 이 때 2차원 다이나믹 프로그래밍을 이용해야한다.
이 배열의 의미는 즉
D[x][0]에 있는 수는 0칸,1칸,2칸,3칸... 일 때의 경우의 수를 넣는 것이다.
근데 이 경우의 수를 넣을려면
3*DP(x-2)+2*DP(x-1); 이식을 넣어야한다.
그래서 DP[4][0] = DP[2][0] * 3 + DP[3] * 2 이러한 식이 완성된다.
하지만 또 4칸일때 5칸일 때... 생기는 2가지의 경우의 수도 더해줘야한다.
그래서 배열 d[2][1]에 1을 넣어준다(아까 x==1 일 때 return 1 넣어준 것처럼) 거기에 2를 곱하고 결과에 더해준다.
let fs = require('fs');
let input = fs.readFileSync('/dev/stdin').toString().split(' ');
let N = Number(input);
var d =Array.from({length:1000001},()=>Array(2).fill(0));
d[0][0] = 1;
d[1][0] = 2;
d[2][0] = 7;
d[2][1] = 0;
for(var i = 3; i <= N; i++) {
d[i][1] = ( d[i - 1][1] + d[i - 3][0]) % 1_000_000_007
d[i][0] = ( 3 * d[i - 2][0] + 2 * d[i - 1][0] + 2 * d[i][1]) % 1_000_000_007
}
console.log(d[N][0]);
https://blog.naver.com/ndb796/221233586932
'알고리즘' 카테고리의 다른 글
플로이드 와샬(Floyd warshall)알고리즘 (0) | 2023.06.02 |
---|---|
다익스트라 알고리즘 (2) | 2023.06.02 |
다이나믹 프로그래밍(Dynamic Programming) - 타일링 문제 (0) | 2023.05.31 |
다이나믹 프로그래밍(Dynamic Programming) - 메모제이션 (0) | 2023.05.31 |
그래프 이론 (이진트리의 구현과 순회방식) (0) | 2023.05.31 |