Thinking about it:
对于一个长度为N的序列,最大的数字为N,那么如果要将它放回到第N个位置,那么最多需要2步。
先用例子简单证明一下:
假设序列:1 2 3 6 5 4,当前最大数为6,需要和4交换位置,那么可以看作:* * * 6 * 4,因为6和4之间有一个数,而6之前有三个数,那么可以之间把6之后的部分,与6(包括)之前的 等长部分交换,可得 : 1 2 5 4 3 6,此时只需要一步,即可。 若如果,6之前的数 小于 6与4之间的数呢,如 1 6 2 3 4 5 ? 那么可以把4之前的整个一部分进行交换,可得:2 3 1 6 4 5,此时有可以从复刚才那一步了。
你可能会问,为什么交换一半就一定能重复上一步能。其实这是可以证明的,假设 6 之前的数总共有 x 个, 而 6 与 4 之前的数有 y 个,且 x < y,假设交换一半,那么6 之前的数有(x + (x+y+1)/2)个数,而6 和 4 之间的数为 ( (x+y+1)/2 - x - 1),虽然可能会因为x+y+1的奇偶性产生一点变化,但相对大小已经确定,也就是变换后 6 之前的数项 仍旧会大于等于 6和4之间的数项
综上可得:
对于一个长度序列为N的序列可以依次将N,N-1,N-2,... ,3, 2 放回原处,而每一次放置最多两步,所以总共最多2N步。
Reference:
1.《算法竞赛入门经典(第2版)》
PS:
刚开始用冒泡的思想,交换邻近的数,但需要N^2次交换,必然不符提议。后来想到,要将当前最大的数放到最后,不一定需要通过交换邻近的两个数,可以试着在一步操作时,交换更多的数,这样对于要交换的数来说,移动的距离大了,但操作只是计入一步而已。
Code:
/** * AC @ Sep 16th 2015 * Run Time : 0.322s */ #include <bits/stdc++.h> using namespace std; typedef std::pair<int, int> Node; vector<int> crane_vec; vector< Node > ans; int N; int search(vector<int> &lst, int value) { for (vector<int>::iterator it = lst.begin(); it != lst.end(); ++it) { if (*it == value) { return it - lst.begin(); } } return -1; } void read() { crane_vec.clear(); ans.clear(); // ensure that the first element is counted from 1 ans.push_back(make_pair(0, 0)); crane_vec.push_back(-1); cin >> N; int tmp; for (int i = 0; i < N; ++i) { cin >> tmp; crane_vec.push_back(tmp); } } // swap from start to end as the problem tells void swap(int start, int end) { ans.push_back(make_pair(start, end)); int mid = (start + end) >> 1; for (int i = start; i <= mid; ++i) { int t = crane_vec[i]; crane_vec[i] = crane_vec[mid + 1 + i - start]; crane_vec[mid + 1 + i - start] = t; } } void done() { int target; while(N > 1) { if (crane_vec[N] != N) { target = search(crane_vec, N); // fr : the useless element(s) before N // bk : the useless element(s) between N and the last element in crane_vec int fr = target - 1; int bk = N - target - 1; if (fr < bk) { // odd or even : the seap operation must need even elements swap(1, N & 1 ? N - 1 : N - 2); target = search(crane_vec, N); fr = target - 1; bk = N - 1 - target; } swap(N - 2 * bk - 1, N); } N --; } } void out() { cout << ans.size() - 1<< endl; for (vector< Node >::iterator it = ans.begin() + 1; it != ans.end(); ++it) { cout << it->first << " " << it->second << endl; } } void work() { read(); done(); out(); } int main() { ios::sync_with_stdio(false); cin.tie(0); int T; cin >> T; while (T --) { work(); } return 0; }