Search
Duplicate
📒

다리놓기

주차
12주차
문제번호
1010
언어
티어
실버
유형
DP
수학
조합론
nj_Blog
nj_상태
이해도
66%
풀이
사람
이해도 2
13 more properties

문제접근

1.
첫번째 접근
강 서쪽의 N개의 사이트에서 강 동쪽의 M개의 사이트를 연결 짓는 경우의 수를 찾는 문제이다.
mCn=m!(mn)!×n!mCn = \frac {m!}{(m-n)!\times n!}
위의 식을 구현을 하면 되는 문제이고, 조합관련 함수 안에 factorial 연산을 하는 함수를 따로 만들어 구현을 하면 될 거 같다.
factorial 연산이 세번이 필요하여 그때마다 재귀호출을 통해서 구하는 것보다 m! 전까지를 memoization을 해두고 쓰게 되면 반복적인 계산 과정을 생략 할 수 있어서 더 효율적이지 않을까 생각한다.
//pseudo code vector<double> dp while (m까지) dp[i] = dp[i-1] * i void combination() { cout << dp[m] / (dp[m-n] * dp[m]) }
C++
복사
→ 자료형에 대해 고려가 부족

놓쳤던 부분

mCn=m!(mn)!×n!mCn = \frac {m!}{(m-n)!\times n!}
이 공식을 사용하게 되면 나누는 과정에서 쓸 자료형이 애매해지게 된다.
long long 을 사용해서는 오버플로우가 나기 때문에 원하는 결과를 얻을 수 없고, double 을 사용하는 것은 오차범위 때문에 정확한 값을 얻을 수가 없어진다.
따라서, iomanip 헤더에서 정밀도 조정을 통해서 출력값을 조정했다

코드

2016 KB

0 ms

#include <iostream> #include <vector> #include <iomanip> std::vector<double> dp; int t; int n, m; void input_setting() { std::ios_base::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); } void input() { std::cin >> t; } void factorial_memoization() { int i = 1; dp[0] = 1; dp[1] = 1; while (++i <= m) dp[i] = dp[i - 1] * i; } void solution() { std::cout << std::setprecision(15); while (t--) { std::cin >> n >> m; dp.resize(m + 1); factorial_memoization(); std::cout << dp[m] / (dp[m - n] * dp[n]) << "\n"; } } int main(void) { input_setting(); input(); solution(); return (0); }
C++
복사