29.2 문제: Sorting Game ( 문제ID : SORTGAME, 난이도: 중)

[algo] : https://www.algospot.com/judge/problem/read/SORTGAME

문제 이해

그래프로 바꾸기

int bfs(const vector<int>& perm){
    int n = perm.size();
    // 목표 정점을 미리 계산한다.
    vector<int> sorted = perm;
    sort(sorted.begin(), sorted.end());
    // 방문 목록(큐)과 시작점부터 각 정점까지의 거리
    queue<vector<int> > q;
    map<vector<int>,int> distance;
    // 시작점을 큐에 넣는다.
    distance[perm] = 0;
    q.push(perm);
    while(!q.empty()){
        vector<int> here = q.front(); q.pop();
        // 목표 정점을 발견했으면 곧장 종료한다.
        if(here == sorted) return distance[here];
        int cost = distance[here];
        // 가능한 모든 부분 구간을 뒤집어 본다.
        for(int i = 0; i < n; ++i){
            for(int j = i + 2; j <= n; j++){
                reverse(here.begin()+i, here.begin() + j);
                if(distance.count(here) == 0){
                    distance[here] = cost + 1;
                    q.push(here);
                }
                reverse(here.begin()+i, here.begin() + j);
            }
        }
    }
    return -1;
}

너무 느리다

1. 숫자들이 다르더라도 상대적인 크기가 같은 배열들에 대한 답은 항상 같습니다. 예를 들어 두 배열
   {30,40,10,20}과 {3,4,1,2}는 숫자들의 상대적 크기가 같기 때문에 필요한 최소 연산 수도 2로
   같습니다.
2. 이 문제의 상태 공간은 양방향 그래프이기 때문에, 시작 정점에서 목표 정점으로 가는 최단 거리는 목표
   정점에서 시작 정점으로 가는 최단 거리와 같습니다. 다시 말해 한 배열을 정렬하는 데 드는 연산의
   수는 정렬된 배열을 원래 배열로 바꾸는 데 드는 연산의 수와 같다는 말입니다.
map<vector<int>, int> toSort;
// [0, .. , n-1]의 모든 순열에 대해 tosort[] 를 계산해 저장한다.
void precalc(int n){
    vector<int> perm(n);
    for(int i = 0; i < n; i++)perm[i] = i;
    queue<vector<int> > q;
    q.push(perm);
    toSort[perm] = 0;
    while(!q.empty()){
        vector<int> here = q.front(); q.pop();
        int cost = toSort[here];
        for(int i = 0; i < n; ++i){
            for(int j = i + 2; j <= n; ++j){
                reverse(here.begin() + i, here.begin() + j);
                if(toSort.count(here) == 0){
                    toSort[here] = cost+1;
                    q.push(here);
                }
                reverse(here.begin() + i, here.begin() + j);
            }
        }
    }
}
int solve(const vector<int>& perm){
    // perm을 [0, .. n-1]의 순열로 변환한다.
    int n = perm.size();
    vector<int> fixed(n);
    for(int i = 0; i < n; i++){
        int smaller = 0;
        for(int j = 0; j < n; j++){
            if(perm[j] < perm[i])
                ++smaller;
        }
        fixed[i] = smaller;
    }
    return toSort[fixed];
}