题目
N个外星人围成一桌坐下,有序的排列指N在N-1与N+1中间,现在给出一个序列,问至少交换几次可以得到有序的序列。5
思路
这道题就有点迷了。。
按这个数据范围,铁铁的是暴力枚举。但是不感觉紫书这一章的习题该考暴力枚举。
就说暴力枚举吧,总感觉枚举的方法也很有问题。AC代码是看别人的写的,每次选一个数作为序列起点,这样一个一个排下去。然后代码2是我之前的思路,每次选一个位置作为起点,随后像冒泡排序一样一个个排下去。
代码2WA,我还找到了反例:3 2 4 5 1 6 。代码2会输出3,实际2即可。
但是对于AC代码的思路,我也证明不了它的正确性。。
所以这道题就这样吧,意思不大。
AC代码
#include "stdafx.h"
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 500 + 10;
int n, A[maxn], ans, temp[maxn];
void solve() {
_rep(i, 1, n) { //选择哪个数字作为序列起点
memcpy(temp, A, sizeof(A));
int cnt = 0;
_rep(j, 0, n - 1) { //A[i-1+j]是遍历到的点
if (temp[j] != (i - 1 + j) % n + 1) {
int *p = find(temp, temp + n, (i - 1 + j) % n + 1);
swap(temp[j], *p);
cnt++;
}
}
ans = min(ans, cnt);
}
}
void myswap() {
int L = 0, R = n - 1;
while (L < R) {
swap(A[L], A[R]);
L++;
R--;
}
}
int main() {
while (scanf("%d", &n) == 1 && n) {
_for(i, 0, n) scanf("%d", &A[i]);
if (n == 1) {
printf("0\n");
continue;
}
ans = maxn;
solve(); // 升序
myswap(); // 升序变降序
solve(); // 降序
printf("%d\n", ans);
}
return 0;
}
代码2
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int maxn = 500 + 10;
int n, A[maxn], ans, temp[maxn];
void solve() {
_for(i, 0, n) { //选择排序起点
memcpy(temp, A, sizeof(A));
int cnt = 0;
_rep(j, 1, n - 1) { //A[i+j]是遍历到的点
if (temp[(i + j) % n] != temp[(i + j - 1) % n] + 1) {
int *p = find(temp, temp + n, temp[(i + j - 1) % n] == n ? 1 : temp[(i + j - 1) % n] + 1);
swap(temp[(i + j) % n], *p);
cnt++;
}
}
ans = min(ans, cnt);
}
}
void myswap() {
int L = 0, R = n-1;
while (L < R) {
swap(A[L], A[R]);
L++;
R--;
}
}
int main() {
while (scanf("%d", &n) == 1 && n) {
_for(i, 0, n) scanf("%d", &A[i]);
if (n == 1) {
printf("0\n");
continue;
}
ans = maxn;
solve(); // 升序
myswap(); // 升序变降序
solve(); // 降序
printf("%d\n", ans);
}
return 0;
}