题意:给出一组数,要求从小到大排序,并且排序的过程中,发生交换的两个数至少一个为幸运数(十进制位均为4或7),问能否在(2×n)次交换内完成排序,如果能,输出交换的方案(不要求步骤数最少)。
思路:首先分为两种情况:
1.所有的数均不为幸运数,则如果给出的序列已经排好序,答案为0,如果未排好序,则无法完成排序。
2.存在幸运数,可得,只要存在幸运数,就一定能在2×n次以内完成排序。
<1>具体的处理方法是将序列分为若干个闭环,闭环的意思可以举个例子来看,(xio表示下标为xi的元素排序后所在位置下标),如:x1->x2->x3->x1,这就是一个闭环,表示x1o==x2,x2o=x3,x3o=x1;
<2>首先,一组数在上述规则下一定能分为若干闭环。
<3>分完闭环后,正式进行交换,并且,确定一个幸运数作为操作数(需要且只需要一个),记录其所在闭环
3.1首先,将操作数所在闭环进行排序(只需相邻之间两两交换即可,具体可参照上文对于闭环的定义)。
3.2再借助操作数对剩余闭环依次排序。第一步为将操作数与待排序闭环中的任意元素交换,再用3.1中的方法操作,最后将操作数归位即可。
3.3很容易证明,上述交换操作的总复杂度一定小于2×n.
代码如下:
#include <cstdio> #include <iostream> #include <queue> #include <algorithm> #include <cstring> using namespace std; typedef pair<int, int> P; int n, arr[100010], inde[100010]; bool judge(int x) { while (x != 0) { if (x % 10 != 4 && x % 10 != 7) return false; x /= 10; } return true; } bool cmp(int a, int b) { return arr[a] < arr[b]; } int main() { int px = 0; scanf("%d", &n); for (int i = 1; i <= n; i++) inde[i] = i; for (int i = 1; i <= n; i++) { scanf("%d", &arr[i]); if (!px && judge(arr[i])) px = i; } sort(inde + 1, inde + 1 + n, cmp); int iinde[100010]; for (int i = 1; i <= n; i++) { iinde[inde[i]] = i; } if (!px) { int tans = 0; for (int i = 1; i <= n; i++) if (inde[i] != i) { tans = -1; break; } printf("%d", tans); } else { vector<P> ans; int book[100010] = {0}; vector<int> aha[100010]; int numAha[100010] = {0}, rd = 0, fgp; for (int i = 1; i <= n; i++) { if (book[i]) continue; rd++; int p = i; while (!book[p]) { book[p] = 1; aha[rd].push_back(p); if (p == px) fgp = rd; p = inde[p]; } } //flagRound memset(book, 0, sizeof(book)); if (aha[fgp].size() > 1) { int ic = px; while (!book[inde[ic]]) { book[ic] = 1; ans.push_back(P(ic, inde[ic])); ic = inde[ic]; } } //restRound for (int i = 1; i <= rd; i++) { if (i == fgp || aha[i].size() == 1) continue; int ic = aha[i][0]; ans.push_back(P(iinde[px], ic)); while (!book[inde[ic]]) { book[ic] = 1; ans.push_back(P(ic, inde[ic])); ic = inde[ic]; } ans.push_back(P(iinde[px], iinde[aha[i][0]])); } printf("%d\n", ans.size()); for (int i = 0; i < ans.size(); i++) { printf("%d %d\n", ans[i].first, ans[i].second); } } return 0; }