题意:给定一个排列,每次可交换两个数,用最少的次数把它变成一个1~n的环状排列。
析:暴力题。很容易想到,把所有的情况都算一下,然后再选出次数最少的那一个,也就是说,我们把所有的可能的形成环状排列全算一下,然后选出最少的。
那么就开一个两倍的数组,然后两遍从1到n,然后每次选 n 个,进行暴力,每找一个不同的,就去找这个位置应该放的,然后交换。注意两次正序和逆序暴力。
#include <iostream> #include <cmath> #include <cstdlib> #include <set> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; const int INF = 0x3f3f3f3f; const int maxn = 500 + 5; int a[maxn], b[maxn<<1], c[maxn], d[maxn<<1]; int main(){ int n; while(scanf("%d", &n) == 1 && n){ int ans = INF; for(int i = 0; i < n; ++i){ scanf("%d", a+i); b[i] = i+1; } memcpy(b+n, b, sizeof(int)*n); memcpy(c, a, sizeof(a)); for(int k = 0; k < n; ++k){ int cnt = 0; memcpy(a, c, sizeof(a)); for(int i = 0, j = k; i < n && cnt < ans; ++j, ++i){ if(a[i] == b[j]) continue; for(int l = i+1; l < n; ++l) if(b[j] == a[l]){ a[l] = a[i]; a[i] = b[j]; break; } ++cnt; } ans = min(ans, cnt); } for(int i = 0; i < n; ++i) d[i] = n-i; memcpy(d+n, d, sizeof(int)*n); for(int k = 0; k < n; ++k){ int cnt = 0; memcpy(a, c, sizeof(a)); for(int i = 0, j = k; i < n && cnt < ans; ++j, ++i){ if(a[i] == d[j]) continue; for(int l = i+1; l < n; ++l) if(d[j] == a[l]){ a[l] = a[i]; a[i] = d[j]; break; } ++cnt; } ans = min(ans, cnt); } printf("%d\n", ans); } return 0; }
代码如下: