[暴力枚举] UVa10570 外星人聚会 (本题价值--)

本文探讨了一种针对特定外星人序列的排序问题,通过枚举起点来找到最少交换次数实现序列排序的方法,并对比了两种不同的排序策略,发现直接以元素为起点的策略更优。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值