본문 바로가기
백준

[백준 17088] 등차수열 변환, C++

by 황인태(intaehwang) 2020. 2. 2.
반응형

https://www.acmicpc.net/problem/17088

 

17088번: 등차수열 변환

크기가 N인 수열 A = [A1, A2, ..., AN]이 있을 때, 모든 1 ≤ i < N에 대해서, Ai+1-Ai가 모두 일치하면 등차수열이라고 한다. 예를 들어, [3], [6, 6, 6], [2, 8, 14, 20], [6, 4, 2]는 등차수열이고, [4, 5, 4], [6, 3, 1]은 등차수열이 아니다. 수열 B = [B1, B2, ..., BN]을 등차수열로 변환하려고 한다. 각각의 수에는 연산을 최대 한 번 적용할 수 있다. 연산은 두 가

www.acmicpc.net

 본 문제는 주어진 수열을 등차수열로 변환하는 문제로 각각의 수에 연산을 최대 한 번 적용할 수 있고, 연산은 1을 더하거나 빼는 것만 가능하다. 주어진 수열을 등차수열로 변환하기 위해 필요한 연산 횟수의 최솟값을 구하는 문제다. 조건 중에 등차수열로 변환시킬 수 없다면 -1을 출력한다.

처음으로 생각난 코드는 brute force였다. 모든 경우를 다 만들고, 등차수열 여부를 검사하는 방법을 선택했다.

  1. 0번 index 부터 시작
  2. 1을 더하는 경우
  3. 1을 빼는 경우
  4. 연산을 안하는 경우
  5. 등차수열 확인

 

brute force

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
#include <cstdio>
#include <vector>
 
using namespace std;
 
int n;
int ans = -1;
 
vector<int> v;
void cal(int index, vector<int> &u, int cnt) {
    if (index == v.size()) {
        // 등차수열 확인
        int chk = u[1- u[0];
        for (int i = 2; i < v.size(); i++) {
            if (u[i] - u[i-1!= chk) return;
        }
        if (ans == -1 || ans > cnt) ans = cnt;
        return;
    }
    // 1을 더하는 경우
    u.push_back(v[index]+1);
    cal(index+1, u, cnt+1);
    u.pop_back();
 
    // 1을 빼는 경우
    u.push_back(v[index]-1);
    cal(index+1, u, cnt+1);
    u.pop_back();
 
    // 연산을 안하는 경우
    u.push_back(v[index]);
    cal(index+1, u, cnt);
    u.pop_back();
 
}
 
int main() {
    scanf("%d"&n);
    for (int i = 0; i < n; i++) {
        int tmp;
        scanf("%d"&tmp);
        v.push_back(tmp);
    }
    vector<int> u;
    // 0번 index 부터 시작
    cal(0, u, 0);
    printf("%d\n", ans);
}
cs

 

그러나 시간초과를 받았다. 모든 경우의 수 중, 등차 수열이 될 가능성이 없는 연산은 할 필요가 없다. 즉, back tracking을 이용해야 한다.

초기 등차수열의 크기는 9가지 경우밖에 없다. 9가지 경우 중에서 등차 수열이 되는 모든 경우의 수를 찾자

  1. 초기 등차수열의 크기 정하기
  2. 연산을 안하는 경우
  3. 1을 더하는 경우
  4. 1을 빼는 경우
  5. 등차 수열이 아닌 경우

어라? 이번엔 틀렸다. 왜 틀렸을까?

입력의 크기를 보면 1부터 시작이다. 그렇기 때문에 등차수열의 크기가 1인 경우를 예외처리한다.

 

back tracking

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
#include <cstdio>
#include <vector>
 
using namespace std;
 
int n;
int ans = -1;
 
vector<int> v;
// x < y
void cal(int x, int y, int index, int cnt) {
    if (index == v.size()) {
        if (ans == -1 || ans > cnt) ans = cnt;
        return;
    }
    int tmp = y - x;
    // 연산을 안하는 경우
    if (v[index] - y == tmp) cal(y, v[index], index+1, cnt);
    // 1을 더하는 경우
    else if (v[index]+1 - y == tmp) cal(y, v[index]+1, index+1, cnt+1);
    // 1을 빼는 경우
    else if (v[index]-1 - y == tmp) cal(y, v[index]-1, index+1, cnt+1);
    // 등차수열이 아닌 경우
    else return;
}
 
int main() {
    scanf("%d"&n);
    for (int i = 0; i < n; i++) {
        int tmp;
        scanf("%d"&tmp);
        v.push_back(tmp);
    }
    // 등차수열의 크기가 1인 경우
    if (n == 1) {
        printf("0\n");
        return 0;
    }
    vector<int> u;
    
    // 초기 등차수열의 크기 정하기
    cal(v[0], v[1], 20);
    cal(v[0], v[1]+121);
    cal(v[0], v[1]-121);
 
    cal(v[0]+1, v[1], 21);
    cal(v[0]+1, v[1]+122);
    cal(v[0]+1, v[1]-122);
 
    cal(v[0]-1, v[1], 21);
    cal(v[0]-1, v[1]+122);
    cal(v[0]-1, v[1]-122);
    
    printf("%d\n", ans);
}
cs
반응형

'백준' 카테고리의 다른 글

[백준 10816] 숫자 카드 2, C++  (0) 2020.02.05
[백준 17089] 세 친구, C++  (0) 2020.02.04
[백준 16932] 모양 만들기, C++  (0) 2020.01.31
[백준 16236] 아기 상어, C++  (0) 2020.01.31
[백준 15686] 치킨 배달, C++  (0) 2020.01.31
Buy me a coffeeBuy me a coffee

댓글