algospot : https://algospot.com/judge/problem/read/ROOTS

github : https://github.com/junho0956/Algorithm

 

algospot ROOTS 단변수 다항 방정식 해결하기 문제입니다.

풀이는 코드에 주석처리 되어있으며 문제해결기법을 참조하였습니다.

 

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
실수 근만을 갖는 ax2 + bx + c = 0과 같은 형태의 단변수 다항 방정식이 주어질 때
이들의 근을 계산하는 프로그램을 작성하세요.
*/
 
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
 
// 모든 해의 절대값은 10 이하라고 가정해도 좋습니다.
const int L = 10;
 
// 단일 변수 다항식p의 계수가 주어질 때 미분한 결과 p'의 계수를 반환한다
vector<double> differentiate(const vector<double>& poly) {
    int n = poly.size() - 1;
    vector<double> res;
 
    for (int i = 0; i < n; i++) {
        res.push_back(poly[i] * (n - i));
    }
    return res;
}
 
// 1차 혹은 2차 방정식을 푼다
vector<double> solveNative(const vector<double>& poly) {
    int n = poly.size() - 1;
    vector<double> res;
    if (n == 1) {
        res.push_back((-1* (poly[1/ poly[0]));
        return res;
    }
    if (n == 2) {
        double a, b, c;
        a = poly[0], b = poly[1], c = poly[2];
        res.push_back(((-b) + (sqrt(pow(b, 2- 4 * a * c))) / (2 * a));
        res.push_back(((-b) - (sqrt(pow(b, 2- 4 * a * c))) / (2 * a));
        sort(res.begin(), res.end());
        return res;
    }
}
 
// 다항식 f(x)의 계수 poly가 주어질 때, f(val)를 반환한다
double evaluate(const vector<double>& poly, double val) {
    double ans = 0;
    int n = poly.size() - 1;
    for (int i = 0; i <= n; i++) {
        ans += pow(val, n - i) * poly[i];
    }
 
    return ans;
}
 
// 방정식의 근을 반환한다
vector<double> solve(const vector<double>& poly) {
    
    // 방정식의 계수를 확인한다
    int n = poly.size() - 1;
 
    // 만약 2차 이하라면 바로 해결한다
    if (n <= 2return solveNative(poly);
 
    // 3차 이상이라면 미분한 방정식을 구한다
    vector<double> different = differentiate(poly);
    // 미분한 방정식에 대한 극점을 재귀를 통하여 구한다
    vector<double> sol = solve(different);
 
    // 왼쪽, 오른쪽 끝의 극점은 그 옆에 또 다른 극점이 존재하지 않으므로 근을 구할 수 없다.
    // 그러므로 초기화 해놓은 L을 이용하여 근을 구한다.
    sol.insert(sol.begin(), -- 1);
    sol.insert(sol.end(), L + 1);
 
    // 각 극점을 이분법을 이용하여 근을 구한다
    vector<double> res;
 
    for (int i = 0; i < sol.size()-1; i++) {
        double x1 = sol[i], x2 = sol[i + 1];
        double y1 = evaluate(poly, x1), y2 = evaluate(poly, x2);
 
        // y가 같은 부호이면 근이 존재할 수 없다.
        if (y1 * y2 > 0continue;
        // 불변 조건 : 이분법의 진행과정에 따라 반드시 f(x1) < f(x2) 일 수는 없다.
        // f(x1) <= 0 < f(x2) 를 강제하여 이분법 상의 두 부분중 어느곳을 선택해야 할지 판단한다.
        if (y1 > y2) {
            swap(y1, y2);
            swap(x1, x2);
        }
        // while 이 아닌 최대 100 정도의 for문으로 이분법을 돌리는 것은
        // 이분법 과정에서 무한루프를 방지할 수 있다.
        for (int i = 0; i < 100; i++) {
            double x = (x1 + x2) / 2;
            double y = evaluate(poly, x);
 
            if (y <= 0) x1 = x;
            else x2 = x;
        }
 
        res.push_back(x1);
    }
    sort(res.begin(), res.end());
    return res;
}
 
int main() {
    ios::sync_with_stdio(0), cin.tie(0);
 
    // 입력의 첫 줄에는 테스트 케이스의 수 C(C<=50)가 주어집니다.
    // 각 테스트 케이스의 첫 줄에는 방정식의 차수 n(2 <= n <= 5)이 주어지고,
    // 그 다음 줄에 n+1개의 실수로 방정식의 차수가 고차항부터 주어집니다.
 
    int C; cin >> C;
    while (C--) {
        int n; cin >> n;
        vector<double> poly;
        for (int i = 0; i < n + 1; i++) {
            double val; cin >> val;
            poly.push_back(val);
        }
        // 각 테스트 케이스마다 n개의 실수로 오름차순으로 정렬된 방정식의 해를 출력합니다.
        // 방정식의 해는 모두 다르다고 가정해도 좋습니다.
        // 10 - 8 이하의 상대 / 절대 오차가 있는 답은 정답으로 처리됩니다.
        vector<double> res = solve(poly);
        sort(res.begin(), res.end());
 
        cout << fixed;
        cout.precision(10);
        for (int i = 0; i < res.size(); i++) {
            cout << res[i] << " ";
        }
        cout << endl;
    }
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

'algorithm > algospot' 카테고리의 다른 글

algospot PASS486  (0) 2020.02.27
algospot FOSSIL  (0) 2020.02.26
algospot RATIO  (0) 2020.02.25
algospot LOAN  (0) 2020.02.24
algospot FESTIVAL  (0) 2019.10.27

문제 : https://www.algospot.com/judge/problem/read/FESTIVAL

 

문제난이도 : 알고리즘 문제해결전략(하)

 

이해를 간단히 돕자면

N 일간의 콘서트장 대여비를 미리 알고있는 상황에서 최소 L 개의 팀이 주어졌을때 (팀의 수는 이미정해진팀+@ )

몇일을 대여하는 것이 평균적으로 가장 싼 비용이 되는가 하는 문제이다.

* 단, 연속해서 대여해야 한다.

 

문제를 접근해보자면

눈에 띄는 것이 연속해서 대여한다는 점이였다.

결국 구간합에대한 구간크기의 길이로 나눈 값이 제일 작은 비용을 찾으면된다.

 

N의 범위는 1-1000이고 시간제한은 2초, 테스트케이스는 최대 100개

그냥 무난하게 2중포문으로 반복문만 돌려도 100N^2 이여서 무난히 시간을 통과할 것 같았다.

 

나는 간단히

1 2 3 1 2 3 이라는 대여값을 받으면

1 3 6 7 9 12 이렇게 값을 연속으로 더해놓고,

L의 최소값부터 L 이 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
#include <cstdio>
#pragma warning(disable:4996)
int arr[1001];
int dp[1001];
int main() {
    int T, N, L;
 
    scanf("%d"&T);
    while (T--) {
        scanf("%d%d"&N, &L);
 
        for (int i = 1; i <= N; i++)
            scanf("%d"&arr[i]);
 
        for (int i = 1; i <= N; i++) {
            dp[i] = dp[i - 1+ arr[i];
        }
 
        double min = (double)dp[L]/L;
        double check;
        for (int i = L; i <= N; i++) {
            for (int k = i; k <= N; k++) {
                check = (double)(dp[k] - dp[k - i]) / i;
                if (check < min) min = check;
            }
        }
        printf("%.10f\n", min);
    }
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter

'algorithm > algospot' 카테고리의 다른 글

algospot PASS486  (0) 2020.02.27
algospot FOSSIL  (0) 2020.02.26
algospot RATIO  (0) 2020.02.25
algospot LOAN  (0) 2020.02.24
algospot ROOTS  (0) 2020.02.24

+ Recent posts