[종만북] 문제: ROOTS
문제
$polynomial$과 이 $polynomial$의 해들이 범위 $[-20, 20]$내에 실수로 존재할 때, 해를 찾으시오.
서론
이분법에 대해 연습해봅시다.
알고리즘 구상
아이디어
문제에서 다항함수 $f(x)$의 해는 모두 다르다고 가정하고, 범위 $[-20, 20]$내에 존재한다고 가정합니다.
따라서 $f(x)$의 극점과 극점 사이에는 해가 존재함을 알 수 있습니다. (중간값 정리와 함수의 연속성 이용)
\[[-21, x_1], \, [x_1, x_2], \, \ldots, [x_{n-2}, x_{n-1}], [x_{n-1}, 21], \quad \text{where } x_1, x_2, \ldots, x_{n-1} \text{ are critical points.}\]수학적으로 정리하면, 이 구간 내에 해가 존재한다고 알 수 있습니다.
알고리즘 설계
$f(x)$의 critical points는 $f’(x)$가 $0$인 $x$를 의미합니다. 재귀적으로 풀 수 있을 것 처럼 보입니다.
$solve(f(x))$가 해를 구하는 알고리즘이라고 가정해봅시다.
base case: 차수가 2 이하라면, 근의 공식이나 대입을 통해 값을 구합니다.
recursive case: $solve(f’(x))$를 통해 도함수의 해를 구하면, 이 해들은 $f(x)$의 극점이므로
\[[-21, x_1], \, [x_1, x_2], \, \ldots, [x_{n-2}, x_{n-1}], [x_{n-1}, 21], \quad \text{where } x_1, x_2, \ldots, x_{n-1} \text{ are critical points.}\]각 구간 내에 정확히 하나의 해만 존재하므로, 이분 탐색으로 해를 구하는 알고리즘을 구상할 수 있습니다.
알고리즘 구현
사용할 STL들
$f(x)$의 각 계수를 저장하기 위해 vector<double>
을 이용합니다.
마찬가지로 해를 구하기 위해서, vector<double>
을 이용합니다.
유틸리티 함수
$f(x)$를 구하는 함수, $f’(x)$를 구하는 함수, 이차방정식의 해를 구하는 함수를 구현합니다.
1
2
3
4
5
6
7
8
// 함수와 입력 값이 주어졌을 때, 출력하는 함수
double function(const vector<double> &f, double input) {
double ret = 0.0;
for (int i = 0; i < f.size(); i++) {
ret += f[i] * pow(input, i);
}
return ret;
}
1
2
3
4
5
6
7
8
// 미분했을 때, 차수를 제공하는 함수
vector<double> differentiation(const vector<double> &input) {
vector<double> ret;
for (int i = 1; i < input.size(); i++) {
ret.push_back(input[i] * i);
}
return ret;
}
1
2
3
4
5
6
7
8
9
10
// 이차방정식을 해결하는 함수
vector<double> naive(const vector<double> &input) {
vector<double> ret;
double rand = 0;
double gap = sqrt(input[1] * input[1] - 4 * input[2] * input[0]);
rand = -input[1];
ret.push_back((rand - gap) / (2 * input[2]));
ret.push_back((rand + gap) / (2 * input[2]));
return ret;
}
solve()
n차 방정식의 해를 구하는 함수를 구현합니다.
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
36
37
38
39
40
41
42
43
44
45
46
// n차 방정식의 해를 구하는 함수
vector<double> solve(const vector<double> &input) {
int degree = input.size() - 1;
// base case
if (degree == 2) return naive(input);
// 도함수의 해들, 양 옆에 -20 20을 추가
vector<double> critical_points = solve(differentiation(input));
// 극점들
vector<double> points;
points.push_back(-21.0);
for (int i = 0; i < degree - 1; i++) {
points.push_back(critical_points[i]);
}
points.push_back(21.0);
vector<double> ret;
// 극점들 간의 있는 해를 이분탐색으로 찾음. (문제에서는 있다고 가정)
for (int i = 0; i < points.size() - 1; i++) {
double xlo = points[i], xhi = points[i + 1];
double ylo = function(input, xlo), yhi = function(input, xhi);
// if (ylo * yhi > 0) continue;
if (ylo > yhi) {
swap(ylo, yhi);
swap(xlo, xhi);
}
int it = 100;
while (it--) {
double mid = (xlo + xhi) / 2.0;
double midf = function(input, mid);
if (ylo * function(input, mid) > 0) {
xlo = mid;
ylo = midf;
} else {
xhi = mid;
yhi = midf;
}
}
ret.push_back(xlo);
}
return ret;
}
최종 코드
여기에서 확인하세요!
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.