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];
}