Problem:
Problem D: Double Sorting

Here we describe a typical problem. There are n balls and n boxes. Each ball is labeled by a unique
number from 1 to n. Initially each box contains one of these balls. We can swap two balls in adjacent
boxes. We are to sort these balls in increasing order by swaps, i.e. move the ball labeled by 1 to the first
box, labeled by 2 to the second box, and so forth. The question is how many swaps are needed.

Now let us consider the situation where the balls are doubled, that is, there are 2n balls and n boxes,
exactly two balls are labeled by k for each 1 ≤ k ≤ n, and the boxes contain two balls each. We can swap
two balls in adjacent boxes, one ball from each box. We are to move the both balls labeled by 1 to the
first box, labeled by 2 to the second box, and so forth. The question is again how many swaps are needed.

Here is one interesting fact. We need 10 swaps to sort [5; 4; 3; 2; 1] (the state with 5 in the first box, 4 in
the second box, and so forth): swapping 5 and 4, then 5 and 3, 5 and 2, 5 and 1, 4 and 3, 4 and 2, 4 and
1, 3 and 2, 3 and 1,and finally 2 and 1. Then how many swaps we need to sort [5, 5; 4, 4; 3, 3; 2, 2; 1, 1]
(the state with two 5’s in the first box, two 4’s in the second box, and so forth)? Some of you might think
20 swaps - this is not true, but the actual number is 15.

Write a program that calculates the number of swaps for the two-ball version and verify the above fact.

Input

The input consists of multiple datasets. Each dataset has the following format:

n

ball1,1 ball1,2

ball2,1 ball2,2

...

balln,1 balln,2

n is the number of boxes (1 ≤ n ≤ 8). balli,1 and balli,2 , for 1 ≤ i ≤ n, are the labels of two balls initially
contained by the i-th box.

The last dataset is followed by a line containing one zero. This line is not a part of any dataset and should not be processed.

Output

For each dataset, print the minumum possible number of swaps.

Sample Input

5
5 5
4 4
3 3
2 2
1 1
5
1 5
3 4
2 5
2 3
1 4
8
8 3
4 2
6 4
3 5
5 8
7 1
2 6
1 7
0

Output for the Sample Input

15
9
21

Solution in C++14 (judge verdict: Accepted)

#include <iostream>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <vector>
#include <valarray>
#include <array>
#include <queue>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <complex>
#include <random>

using namespace std;
using ll = long long;
using ull = unsigned long long;

using P = array<int, 16>;

constexpr int B = 10;
unordered_map<ull, int> cor_hb[9];

void first() {
    for (int n = 1; n <= 8; n++) {
        auto p2ull = [&](const P &x) {
            ull a = 0;
            for (int i = 0; i < 2*n; i++) {
                a <<= 4;
                a += x[i];
            }
            return a;
        };
        auto ull2p = [&](ull a) {
            P p = {};
            for (int i = 2*n-1; i >= 0; i--) {
                p[i] = a & 0b1111;
                a >>= 4;
            }
            return p;
        };
        using Q = pair<int, ull>;
        P first = {};
        for (int i = 0; i < n; i++) {
            first[2*i] = first[2*i+1] = i;
        }
        queue<Q> que;
        que.push(Q(0, p2ull(first)));
        while (!que.empty()) {
            int dist; ull xh;
            tie(dist, xh) = que.front(); que.pop();
            P x = ull2p(xh);
            if (cor_hb[n].count(xh)) continue;
            cor_hb[n][xh] = dist;
            if (dist >= B-1) break;
            for (int i = 0; i < n-1; i++) {
                for (int l = 0; l < 2; l++) {
                    for (int r = 0; r < 2; r++) {
                        P y = x;
                        swap(y[2*i+l], y[2*i+2+r]);
                        if (y[2*i+0] > y[2*i+1]) {
                            swap(y[2*i+0], y[2*i+1]);
                        }
                        if (y[2*i+2] > y[2*i+3]) {
                            swap(y[2*i+2], y[2*i+3]);
                        }
                        ull yh = p2ull(y);
                        if (cor_hb[n].count(yh)) continue;
                        que.push(Q(dist+1, yh));
                    }
                }
            }
        }
    }
}
bool solve() {
    int n;
    cin >> n;
    if (!n) return false;
    P a = {};
    for (int i = 0; i < 2*n; i++) {
        int x;
        cin >> x; x--;
        a[i] = x;
    }
    for (int i = 0; i < n; i++) {
        if (a[2*i] > a[2*i+1]) {
            swap(a[2*i], a[2*i+1]);
        }
    }
    if (n == 8) {
        bool allrev = true;
        for (int i = 0; i < n; i++) {
            if (a[2*i] != n-1-i or a[2*i+1] != n-1-i) {
                allrev = false;
                break;
            }
        }
        if (allrev) {
            cout << 40 << endl;
            return true;            
        }
    }
    auto h = [&](const P &x) {
        int sm = 0;
        for (int i = 0; i < n; i++) {
            sm += abs(x[2*i]-i);
            sm += abs(x[2*i+1]-i);
        }
        return sm;
    };
    auto p2ull = [&](const P &x) {
        ull a = 0;
        for (int i = 0; i < 2*n; i++) {
            a <<= 4;
            a += x[i];
        }
        return a;
    };
    auto ull2p = [&](ull a) {
        P p = {};
        for (int i = 2*n-1; i >= 0; i--) {
            p[i] = a & 0b1111;
            a >>= 4;
        }
        return p;
    };
    constexpr int MD = 100;
    unordered_map<ull, int> &cor_h = cor_hb[n];
    // {
    //     using Q = pair<int, P>;
    //     P first = {};
    //     for (int i = 0; i < n; i++) {
    //         first[2*i] = first[2*i+1] = i;
    //     }
    //     queue<Q> que;
    //     que.push(Q(0, first));
    //     while (!que.empty()) {
    //         int dist; P x;
    //         tie(dist, x) = que.front(); que.pop();
    //         if (dist >= B) break;
    //         if (cor_h.count(p2ull(x))) continue;
    //         cor_h[p2ull(x)] = dist;
    //         for (int i = 0; i < n-1; i++) {
    //             for (int l = 0; l < 2; l++) {
    //                 for (int r = 0; r < 2; r++) {
    //                     P y = x;
    //                     swap(y[2*i+l], y[2*i+2+r]);
    //                     if (y[2*i+0] > y[2*i+1]) {
    //                         swap(y[2*i+0], y[2*i+1]);
    //                     }
    //                     if (y[2*i+2] > y[2*i+3]) {
    //                         swap(y[2*i+2], y[2*i+3]);
    //                     }
    //                     que.push(Q(dist+1, y));
    //                 }
    //             }
    //         }
    //     }
    // }
    {
        using Q = pair<int, ull>;
        vector<Q> que[MD];
        que[h(a)/2].push_back(Q(h(a), p2ull(a)));
        int ans = 10000;
        int gc = 0;
        unordered_set<ull> used;
        for (int disth = 0; disth < MD; disth++) {
            sort(que[disth].begin(), que[disth].end());
            que[disth].erase(unique(begin(que[disth]), end(que[disth])), end(que[disth]));
            while (que[disth].size()) {
                gc++;
                P x; ull xhs; int hx;
                tie(hx, xhs) = que[disth].back(); que[disth].pop_back();
                x = ull2p(xhs);
                if (ans <= disth) break;
                if (used.count(xhs)) continue;
                used.insert(xhs);
                if (hx/2 < B and cor_h.count(xhs)) {
                    ans = min(ans, disth-hx/2 + cor_h[xhs]);
                    continue;
                }
                for (int i = 0; i < n-1; i++) {
                    P y = x;
                    int hy = hx;
                    swap(y[2*i+1], y[2*i+2]);
                    hy -= abs(x[2*i+1]-i);
                    hy -= abs(x[2*i+2]-(i+1));
                    hy += abs(y[2*i+1]-i);
                    hy += abs(y[2*i+2]-(i+1));
                    if (y[2*i+0] > y[2*i+1]) {
                        swap(y[2*i+0], y[2*i+1]);
                    }
                    if (y[2*i+2] > y[2*i+3]) {
                        swap(y[2*i+2], y[2*i+3]);
                    }
//                    assert(disth <= disth-hx/2+1+hy/2);
                    int ndisth = disth-hx/2+1+hy/2;
                    ull yhs = p2ull(y);
                    if (ans <= ndisth) continue;
//                    if (used.count(yhs)) continue;
                    que[ndisth].push_back(Q(hy, yhs));
                }
            }
        }
//        cout << ans << " " << used.size() << " " << cor_h.size() << " " << gc << endl;
        cout << ans << endl;
    }
    return true;
}

int main() {
    first();
    while (solve()) {}
    return 0;
}