본문 바로가기

Algorithm/BaekJoon

[2529] 부등호

728x90

구분

  • 백트래킹

 

문제

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

 

2529번: 부등호

여러분은 제시된 부등호 관계를 만족하는 k+1 자리의 최대, 최소 정수를 첫째 줄과 둘째 줄에 각각 출력해야 한다. 단 아래 예(1)과 같이 첫 자리가 0인 경우도 정수에 포함되어야 한다. 모든 입력

www.acmicpc.net

 

 

 

풀이1

먼저 간단하게, 답 배열에 첫번째 자리 수를 집어 넣어놓고 백트래킹을 진행한다.

진행하고, 최댓값 최솟값 String을 갱신하는 방법이다. 

 

코드(8ms)

//
// 부등호
//

#include <iostream>
#include <vector>

using namespace std;

const int SIZE = 10;

long long min_cost = 999999999999;
long long max_cost = 0;
string minString;
string maxString;

int k;
vector<char> v;
bool check[SIZE];
int num[SIZE];//

bool compare(char c, int a, int b) {

    if (c == '>') {
        return a > b;
    } else if (c == '<') {
        return a < b;
    }
}


void backtracking(int cnt, int first) {

	//k개가 들어오면
    if (cnt == k) {
        string s;

        //num배열에 저장된 내용을 string으로
        for (int i = 0; i <= k; i++) {
            s += to_string(num[i]);
        }

        //최대,최소값 갱신
        if (stoll(s) > max_cost) {
            max_cost = stoll(s);
            maxString = s;
        }
        if (stoll(s) < min_cost) {
            min_cost = stoll(s);
            minString = s;
        }
        return;
    }


    // 현재 부호가 뭔지
    char c = v[cnt];

    for (int i = 0; i < SIZE; i++) {

        //사용 ㄴㄴ && num배열 "부호" 지금 검사중인 수 true일때만
        if (!check[i] && compare(c, num[cnt], i)) {

            //다음 칸에 삽입
            num[cnt + 1] = i;
            check[i] = true;

            backtracking(cnt + 1, first);
            check[i] = false;

        }

    }
    return;


}


int main() {


    cin >> k;
    char op;

    for (int i = 0; i < k; i++) {
        cin >> op;
        v.push_back(op);
    }

	//첫번째 자리수는 채워진 상태로 시작
    for (int i = 0; i < SIZE; i++) {
        num[0] = i;
        check[i] = true;
        backtracking(0, i);
        check[i] = false;
    }

    cout << maxString << "\n";
    cout << minString;
}

원래 이렇게 풀었는데, 더 좋은 방법이 있다고 하셔서 공부해서 나름대로 해보았다..거의 비슷하지만(다음방법)

 

풀이2

그 다음은 최대/최소값의 수가 다음과 같다는 사실에 주목한다.

주어지는 부등호의 수가 k개 라면, 

부등호에 비교되는 숫자는 k+1개 이다.  ( k+1은 최대 0~9까지 이므로 10개이다) 

 

그렇다면, 최대값과 최솟값은 숫자의 배열 순서는 알 수 없지만 , 숫자의 구성은 알 수 있다.

최댓값의 구성은 9부터 차례대로 9, 8, ...  총 k+1개 일 것이며,

최솟값의 구성은 0부터 차레대로 0, 1, ... 총 k+1개로 구성되었을 것이다.

그래서 숫자의 구성을 미리 배열에 넣어두고, 해당 배열에 있는 숫자만 가지고 백트래킹을 진행하는 방식이다.

 

 

코드(0ms)

//
// 부등호
//

#include <iostream>
#include <vector>

using namespace std;

const int SIZE = 10;

int k;
vector<char> v(SIZE);//operator 저장
vector<int> num(SIZE);//백트래킹중 답을 저장할 배열 (최대 0~9)
vector<int> num_list(SIZE);//백트래킹에 사용될 숫자 (최대 0~9)
vector<bool> check(SIZE);//0~9
bool is_end = false;

bool compare(char c, int a, int b) {

    if (c == '>') {
        return a > b;
    } else if (c == '<') {
        return a < b;
    }
}


void backtracking(int cnt) {//사용할 숫자 리스트는 한정되어 있음, 배치만하면됨

    //두개의 if문의 순서가 틀리면 오답 -> k+1일떄도 먼저 검사가 진행되어서 오답인지 확인해야함

    if (cnt > 1 && !compare(v[cnt - 2], num[cnt - 2],
                            num[cnt - 1])) //num에 들어간 숫자 2개 이상이어야 비교 가능, 이미 들어간 두개의 수를 비교해야해서 cnt-2, cnt-1
        return; //오답이라서 탈출
    if (cnt == k + 1) {//숫자 k+1개 다쓰면 종료
        is_end = true;//(진 탈출 조건)
        return;
    }


    for (int i = 0; i <= k; i++) {
        //사용 ㄴㄴ
        if (!check[num_list[i]]) {
            //다음 칸에 삽입
            num[cnt] = num_list[i];
            check[num_list[i]] = true;

            backtracking(cnt + 1);
            if (is_end) return;//진 탈출 조건을 만족하면 진짜로 끝

            //원상복귀
            check[num_list[i]] = false;
            num[cnt] = 0;

        }

    }

}


string arrToString(vector<int> &arr) {

    string ans;
    for (int i = 0; i <= k; i++) {
        ans += to_string(arr[i]);
    }

    return ans;
}


int main() {

    string maxString, minString;

    cin >> k;

    //연산자 입력받기 (k개)
    for (int i = 0; i < k; i++) {
        cin >> v[i];
    }


    //최댓값에 사용될 숫자목록(9부터 k+1개)
    for (int i = 0; i <= k; i++) {
        num_list[i] = 9 - i;
    }
    backtracking(0); //해당 숫자목록을 이용해서 백트래킹 진행
    maxString = arrToString(num);//정답을 string으로


    //초기화
    check.assign(SIZE, false);
    num.assign(SIZE, 0);
    is_end = false;


    //최댓값에 사용될 숫자목록(9부터 k+1개)
    for (int i = 0; i <= k; i++) {
        num_list[i] = i;
    }
    backtracking(0); //해당 숫자목록을 이용해서 백트래킹 진행
    minString = arrToString(num);//정답을 string으로


    cout << maxString << "\n";
    cout << minString;


}

 

 

두 가지 방법은 시간 차이가 확실하다. 

탐색해야하는 숫자의 갯수를 한정지어서 검사할 수 있기 떄문인 것 같다.

첫번째 방법에서는 모든 경우에 0-9를 검사하지만, 두번쨰 방법은 k+1개 내에서 검사한다

728x90

'Algorithm > BaekJoon' 카테고리의 다른 글

[2343] 기타 레슨  (0) 2021.10.13
[3190] 뱀  (0) 2021.10.09
[20055] 컨베이어 벨트 위의 로봇  (0) 2021.09.28
[20302] 민트초코  (0) 2021.09.27
[2841] 외계인의 기타 연주  (0) 2021.09.27