알고리즘
[백준/1010] 다리놓기 - 동적계획법/메모이제이션/top-down
명묭
2020. 9. 3. 00:10
dp 너무너무 헷갈린다. 실버 5 푸는데 머리 안돌아가서 하루종일 붙잡고있었네...... 욕심 안부리고 오늘은 dp 이해하기로..^_^..
package silver5;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.StringTokenizer;
public class Main_1010_다리놓기_조합dp {
static int M,N, answer;
static int [][] dp;
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int T = Integer.parseInt(br.readLine());
for(int t=0; t<T; t++) {
StringTokenizer st = new StringTokenizer(br.readLine()," ");
N=Integer.parseInt(st.nextToken());
M=Integer.parseInt(st.nextToken());
dp=new int[M+1][N+1];
answer=0;
for(int m=0; m<M; m++) {
dp[m][0]=1;
dp[m][1]=m;
}
answer = combination(M,N);
// mCn = m-1Cn-1 + m-1Cn
// 4C2 = 3C1 + 3C2
// 2C1 + 2C0 + 2C2 + 2C1
// 1C1+1C0+ 1C0+(1C-1=0)+ (1C2=0)+1C1 + 1C1+1C0
System.out.println(answer);
}
}
// cnt 쓰는거랑 n,r 쓰는거 차이를 알아야됨
// 둘 다 써야하는건가? 진짜 헷갈리네
private static int combination(int n, int r) {
if(n<0||r<0||n<r) {
// System.out.println("범위벗어남");
return 0;
}else if(dp[n][r]>0) {
// System.out.println(dp[n][r]);
return dp[n][r];
}else {
dp[n-1][r]=combination(n-1,r);
dp[n-1][r-1]=combination(n-1,r-1);
// System.out.println("dp[n-1][r] + dp[n-1][r-1] = " + dp[n-1][r] + " / " + dp[n-1][r-1]);
return dp[n-1][r]+dp[n-1][r-1];
}
}
}
순열조합 코드 익히니까 아주 조금 익숙해지긴했는데 한번더 정리하면
1. 규칙찾기 mCn = m-1Cn-1 + m-1Cn
2. 같은 계산이 여러번 반복되면 배열 만들어서 때려넣기 static int [][] dp;
3. combination 함수 만들고,
3-1. 탈출할 부분
3-1-1 if(조합에서 있을수 없는 조건) return 0
3-1-2 if(메모이제이션 되어있는 값이라면) return 그 값
3-2. 재귀 들어갈 부분
끝.... 재귀를 쓸꺼면 탈출하는 부분 신경써야된다그랬음...
+ 좀 헷갈리는부분
지금 코드에서는 초기값.....을 미리 지정해두고 위에서부터 쭈욱 내려갔다가 그 값 발견하면 계산하면서 다시 올라오는건데... 이렇게하는게 맞는건가.... 그냥 처음부터 아래서부터 시작하는건가? 헷갈린다 또 ^_^.... 다음 문제 풀어보면서 다시 정리해봐야지...
참고해볼자료, 읽고 다음문제 풀자
동적계획법(Dynamic Programing, DP)
동적계획법 동적 계획법(Dynamic Programming, DP)은 큰 문제를 작은 문제로 나눠서 푸는 알고리즘이다. 동적 계획법(Dynamic Programming)은 이름만으로 무엇을 의미하는지 알 수 없기 때문에 오해가 많이 ��
coding-all.tistory.com