티스토리 뷰

알고리즘/백준

백준 1039 교환

4567은 소수 2022. 8. 28. 17:52

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

 

1039번: 교환

첫째 줄에 정수 N과 K가 주어진다. N은 1,000,000보다 작거나 같은 자연수이고, K는 10보다 작거나 같은 자연수이다.

www.acmicpc.net

k번을 전부 돌려야 해서 조금 까다로운 문제였습니다. 1,000,000 이하의 수이므로 사실상 6자리라 보면 스왑하는 경우는 총 6C2=15, 10번 진행하므로 나올 수 있는 전체 경우는 15^10개입니다.

 

하지만 이를 모두 확인하는 것은 시간초과가 뻔하므로 (15^10 => 얼추 2^40 정도) 중복을 피해야합니다. 

(ex. 111 은 어떤 경우라도 스왑 시 111 이런 경우를 최소화시켜야 한다.)

 

bfs와 set을 이용해 풀었습니다.

각 라운드 (k번 라운드) 마다 set을 초기화하고 bfs를 이용해 스왑을 진행합니다. 동일 라운드에서 스왑한 것이 set에 포함되어 있다면 해당 값은 더 이상 진행해봤자 동일한 값이 나오므로 set에 넣지 않습니다.

 

그리고 마지막 라운드에서 큐에 남아있는 값들을 비교해 최대값을 고릅니다.

 

-1이 정답인 경우는 1자리 수이거나 2자리 수인데 1의 자리가 0이면 스왑이 불가능하므로 이 경우들은 -1이 정답입니다.

 

코드는 다음과 같습니다.

#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <cstring>
#include <algorithm>

using namespace std;

string n;
int k;
string ans;

void init()
{
    cin >> n;
    cin >> k;
    ans = "";
}

void bfs()
{
    // k번 진행하면서
    // 스왑시킨 것들 전부 큐에 넣기
    // set에 존재하면 동일한 케이스이므로 패스 
    set<string> check;
    set<string>::iterator iter;
    
    queue<string>q;
    
    q.push(n);
    int start = 0;
    int last = n.size() - 1;
    
    for(int i = 0; i < k; i++) {
        
        check.clear();
        
        // k번 진행한 거 구분하기 위해 
        // 이전 큐 사이즈만큼만 진행 
        int q_size = q.size();
        for(int j = 0; j < q_size; j++) {
            string tmp = q.front();
            q.pop();
            
            for(int u = start; u < last; u++) {
                for(int v = u + 1; v <= last; v++) {
                    string swap_tmp = tmp;
                    swap(swap_tmp[u], swap_tmp[v]);
                    
                    iter = check.find(swap_tmp);
                    // 스왑한 거 set에 없음 
                    if(iter == check.end()) {
                        check.insert(swap_tmp);
                        q.push(swap_tmp);
                    }
                }
            }
        }
        
        // k번 진행 시 최대값 구하기 
        if(i == (k - 1)) {
            ans = q.front();
            while(!q.empty()) {
                string tmp = q.front();
                q.pop();
                if(tmp > ans)
                    ans = tmp;
            }
        }
    }
    
    cout << ans;
}

bool fail()
{
    // 불가능한 경우
    // 1자리는 스왑 불가 
    if(n.size() == 1)
        return true;
    // 2자리인데 1의 자리가 0이어도 스왑 불가 
    if(n.size() == 2 && n[0] != '0' && n[1] == '0')
        return true;
    // 나머지는 가능 
    return false;
}

int main()
{
    init();
    
    if(fail())
        cout << -1;
    else
        bfs();
}

'알고리즘 > 백준' 카테고리의 다른 글

백준 1613 역사  (0) 2022.08.31
백준 3372 보드 점프  (0) 2022.08.28
백준 9934 완전 이진 트리  (0) 2022.08.28
백준 10165 버스 노선  (0) 2022.08.16
백준 5582 공통 부분 문자열 C++  (0) 2022.08.12
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
TAG
more
«   2024/12   »
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
글 보관함