#include using namespace std; int n; vector V,VC; vector > CostPos, CostVal; int typePos, typeVal; vector > chains; void findChains() { vector vis(n); for (int i = 0; i < n; ++i) { if (vis[i]) continue; if (V[i] != i) { // found chain! chains.push_back({}); vis[i] = 1; vector& chain = chains.back(); chain.push_back(i); int cur = i; while (!vis[V[cur]]) { vis[V[cur]] = 1; cur = V[cur]; chain.push_back(cur); } } } } void selectionSort() { vector > RES; for (int i = 0; i < n; ++i) { int mnv = V[i]; int mnidx = i; for (int j = i + 1; j < n; ++j) { if (V[j] < mnv) { mnv = V[j]; mnidx = j; } } if (mnidx != i) { RES.push_back({i, mnidx}); swap(V[i], V[mnidx]); } } int rsz = RES.size(); printf("%d\n", rsz); for (int i = 0; i < rsz; ++i) { printf("%d %d\n", RES[i].first + 1, RES[i].second + 1); } } void chainsSolution() { // FIND ALL CHAINS AND SELECT SMALLEST ELEMENT FROM EACH CHAIN // TO MAKE SWAPS WITH IT vector > RES; findChains(); for (auto& chain : chains) { unordered_map chainSet; for (int i = 0; i < (int) chain.size(); ++i) chainSet[chain[i]] = i; int bestCost = INT_MAX; int bestStartingIdx = -1; int csz = chain.size(); for (int startingIdx = 0; startingIdx < csz; ++startingIdx) { int curCost = 0; VC=V; // We can insert random element at the beginning and then // swap with the new random element and then swap with the initial first // change it with the first. // in summary we choose random swap idx and swap the chain with that idx. for (int ic = 1; ic <= csz; ++ic) { int i = (startingIdx + ic) % csz; curCost += CostVal[VC[chain[startingIdx]]][VC[chain[i]]] + CostPos[chain[startingIdx]][chain[i]]; swap(VC[chain[startingIdx]],VC[chain[i]]); } if (curCost < bestCost) { #ifdef DEBUG_TOSHKO printf("BestCost: %d, StartingIdx(in c): %d\n", curCost, chain[startingIdx]); #endif bestCost = curCost; bestStartingIdx = chain[startingIdx]; } } for (int startingIdx = 0; startingIdx < n; ++startingIdx) { if (chainSet.count(startingIdx)) continue; int curCost = 0; VC = V; for (int ci = 0; ci < csz; ++ci) { curCost += CostVal[VC[startingIdx]][VC[chain[ci]]] + CostPos[startingIdx][chain[ci]]; swap(VC[startingIdx],VC[chain[ci]]); } curCost += CostVal[VC[startingIdx]][VC[chain[0]]] + CostPos[startingIdx][chain[0]]; swap(VC[startingIdx],VC[chain[0]]); if (curCost < bestCost) { #ifdef DEBUG_TOSHKO printf("BestCost: %d, StartingIdx(out c): %d\n", curCost, startingIdx); #endif bestCost = curCost; bestStartingIdx = startingIdx; } } if (chainSet.count(bestStartingIdx)) { bestStartingIdx = chainSet[bestStartingIdx]; for (int ic = 1; ic < csz; ++ic) { int i = (bestStartingIdx + ic) % csz; swap(V[chain[bestStartingIdx]],V[chain[i]]); RES.push_back({chain[bestStartingIdx],chain[i]}); } } else { #ifdef DEBUG_TOSHKO printf("\nin else\n"); #endif for (int i = 0; i < csz; ++i) { swap(V[bestStartingIdx],V[chain[i]]); RES.push_back({bestStartingIdx,chain[i]}); } swap(V[bestStartingIdx],V[chain[0]]); RES.push_back({bestStartingIdx,chain[0]}); } } int rsz = RES.size(); printf("%d\n", rsz); for (int i = 0; i < rsz; ++i) { printf("%d %d\n", RES[i].first + 1, RES[i].second + 1); } // THIS WAS CHAINS SOLUTION #ifdef DEBUG_TOSHKO printf("SORTED:\n"); for (int i = 0; i < n; ++i) printf("%d ", V[i]+1); printf("\n"); #endif } vector > RES; int shortestPath(int from, int to, vector& onPlace) { int costDirectSwap = CostVal[V[from]][V[to]] + CostPos[from][to]; int indirectIdx = -1; int costIndirectSwap = INT_MAX; for (int i = 0; i < n; ++i) { if (onPlace[i] || i == from || i == to) continue; int c1 = CostVal[V[from]][V[i]] + CostPos[from][to]; int c2 = CostVal[V[from]][V[to]] + CostPos[i][to]; if (c1 + c2 < costIndirectSwap) { costIndirectSwap = c1 + c2; indirectIdx = i; } } if (costDirectSwap < costIndirectSwap) { /* #ifdef DEBUG_TOSHKO printf("Swapping %d to %d\n",from, to); printf("Cost with direct: %d, cost with indirect: %d\n\n",costDirectSwap, costIndirectSwap); #endif */ onPlace[to] = 1; swap(V[from],V[to]); if (V[from] == from) onPlace[from] = 1; RES.push_back({from, to}); } else { /* #ifdef DEBUG_TOSHKO printf("Swapping %d to %d with indirect idx %d\n",from, indirectIdx, to); printf("Cost with direct: %d, cost with indirect: %d\n\n",costDirectSwap, costIndirectSwap); #endif */ onPlace[to] = 1; swap(V[from],V[indirectIdx]); swap(V[indirectIdx],V[to]); if (V[from] == from) onPlace[from] = 1; if (V[indirectIdx] == indirectIdx) onPlace[indirectIdx] = 1; RES.push_back({from, indirectIdx}); RES.push_back({indirectIdx, to}); } return min(costDirectSwap, costIndirectSwap); } void shortestPathsSolution() { vector onPlace(n); for (int i = 0; i < n; ++i) if (V[i] == i) onPlace[i] = 1; vector onPlaceCp = onPlace; vector VCp = V; vector > RESCp; int bestPrice = INT_MAX; vector bestPerm; vector perm; for (int i = 0; i < n; ++i) perm.push_back(i); while (clock() < 2.5 * CLOCKS_PER_SEC) { onPlace = onPlaceCp; V = VCp; RES = RESCp; int cur = 0; for (int iz = 0; iz < n; ++iz) { int i = perm[iz]; while (V[i] != i) cur += shortestPath(i, V[i], onPlace); } if (cur < bestPrice) { #ifdef DEBUG_TOSHKO printf("Found better solution. Old: %d, New: %d\n", bestPrice, cur); #endif bestPrice = cur; bestPerm = perm; } random_shuffle(perm.begin(), perm.end()); } // EXTRACT BEST SOL; onPlace = onPlaceCp; V = VCp; RES = RESCp; int cur = 0; for (int iz = 0; iz < n; ++iz) { int i = perm[iz]; while (V[i] != i) cur += shortestPath(i, V[i], onPlace); } int rsz = RES.size(); printf("%d\n", rsz); for (int i = 0; i < rsz; ++i) { printf("%d %d\n", RES[i].first + 1, RES[i].second + 1); } #ifdef DEBUG_TOSHKO printf("SORTED:\n"); for (int i = 0; i < n; ++i) printf("%d ", V[i]+1); printf("\n"); #endif } void randomShufflesPlusSelectionSort() { vector > bestSwapsBeforeSelection; vector bestPermForSelection; int bestPrice = INT_MAX; while (clock() < 2.5*CLOCKS_PER_SEC) { int curPrice = 0; vector V_CPY = V; vector > swapsBeforeSelection; vector permForSelection; for (int i = 0; i < n; ++i) permForSelection.push_back(i); random_shuffle(permForSelection.begin(), permForSelection.end()); int swaps = 1 + rand() % n; for (int s = 0; s < swaps; ++s) { int x1 = rand()%n; int x2 = rand()%n; if (x1 != x2) { swapsBeforeSelection.push_back({x1, x2}); curPrice += CostPos[x1][x2] + CostVal[V_CPY[x1]][V_CPY[x2]]; swap(V_CPY[x1], V_CPY[x2]); } } for (int iz = 0; iz < n; ++iz) { int i = permForSelection[iz]; if (V_CPY[i] == i) continue; for (int j = 0; j < n; ++j) { if (V_CPY[j] == i) { curPrice += CostPos[i][j] + CostVal[V_CPY[i]][V_CPY[j]]; swap(V_CPY[i], V_CPY[j]); break; } } } if (curPrice < bestPrice) { #ifdef DEBUG_TOSHKO printf("Found better with %d swaps. Old: %d, New: %d\n", (int) swapsBeforeSelection.size(), bestPrice, curPrice); #endif bestPrice = curPrice; bestSwapsBeforeSelection = swapsBeforeSelection; bestPermForSelection = permForSelection; } } for (auto& s : bestSwapsBeforeSelection) { RES.push_back(s); swap(V[s.first], V[s.second]); } for (int iz = 0; iz < n; ++iz) { int i = bestPermForSelection[iz]; if (V[i] == i) continue; for (int j = 0; j < n; ++j) { if (V[j] == i) { RES.push_back({j, i}); swap(V[i], V[j]); } } } int rsz = RES.size(); printf("%d\n", rsz); for (int i = 0; i < rsz; ++i) { printf("%d %d\n", RES[i].first + 1, RES[i].second + 1); } #ifdef DEBUG_TOSHKO printf("SORTED:\n"); for (int i = 0; i < n; ++i) printf("%d ", V[i]+1); printf("\n"); #endif } int main() { // ios::sync_with_stdio(0); // cin.tie(0); // cout.tie(0); srand(133431); freopen("sorting.in", "r", stdin); freopen("sorting.out", "w", stdout); scanf("%d", &n); V.resize(n); for (int i = 0; i < n; ++i) { scanf("%d", &V[i]); V[i]--; } CostPos.resize(n, vector(n)); CostVal.resize(n, vector(n)); scanf("%d", &typePos); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { scanf("%d", &CostPos[i][j]); } } scanf("%d", &typeVal); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { scanf("%d", &CostVal[i][j]); } } //selectionSort(); //chainsSolution(); //shortestPathsSolution(); randomShufflesPlusSelectionSort(); return 0; }