李星彤 发表于 6 天前

这个冒泡到底哪里有问题

新生入学后,图书馆将
N
N 本书摆在一条书架上。书的编号为
1
,
2
,
…
,
N
1,2,…,N。

目前,这些书的顺序可能是乱的。管理员希望通过调整书的位置,使书架最终变为:第
1
1 个位置放编号
1
1 的书,第
2
2 个位置放编号
2
2 的书,依次类推。

书架前安装了一台轨道机械臂。每次操作时,小蓝可以选择三个连续的位置,机械臂会交换第一个位置和第三个位置上的书,中间位置上的书保持不动。

例如,当前书架顺序为
1
,
2
,
3
,
4
,
5
1,2,3,4,5。选择第
2
2 至第
4
4 个位置后,编号为
2
2 和
4
4 的书会交换,书架变为
1
,
4
,
3
,
2
,
5
1,4,3,2,5。

现在给出书架上
N
N 本书的当前顺序,请你计算,至少需要进行多少次操作,才能将书架恢复为
1
,
2
,
…
,
N
1,2,…,N 的顺序。如果无论如何都无法完成,输出
−
1
−1。


#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
int n ;
scanf("%d",&n);
long long a;
for(int i = 0; i < n; i++)
{
    scanf("%lld",&a);
    if(a % 2 != (i + 1) % 2)
      break;
      printf("-1");
    return 0;
}
long long ans = 0;
for(int j = 0; j < n - 2; j++)
{
    for(int i = 0; i < n - 2; i++)
    if(a > a)
    {
      long long t = a;
      a = a;
      a = t ;
      ans++;
    }
}

printf("%lld", ans);
return 0;
}

FishC 发表于 6 天前

你的代码主要有这些问题:

[*] a 只是一个变量,没有数组,读入时每次都覆盖,后面无法比较和交换。
[*] 奇偶检查的 if 没有大括号,导致 printf("-1"); return 0; 无论条件如何都会执行,程序读第一个数就退出了。
[*] 冒泡里写的是 a > a,自己和自己比,永远不成立;而且交换的也是同一个变量,没有意义。
[*] 循环边界 n-2 不对,且没有对数组操作。
[*] 不能对整个数组直接冒泡排序。题目每次只能交换距离为 2 的两个位置,也就是只能交换奇数位置之间、偶数位置之间。直接冒泡会交换相邻的奇偶位置,这是不允许的。


正确思路:
每次操作交换位置 i 和 i+2,所以:
1. 位置 i 上的书必须和 i 同奇偶,否则无解,输出 -1。
2. 奇数位置上的书只会互相交换,偶数位置上的书也只会互相交换。
3. 最少操作次数 = 奇数位置序列变成升序的逆序数 + 偶数位置序列变成升序的逆序数。

参考代码(用归并排序求逆序数,O(N log N)):

#include <stdio.h>
#include <stdlib.h>

long long merge(int a[], int tmp[], int l, int r) {
    if (l >= r) return 0;
    int mid = (l + r) / 2;
    long long cnt = merge(a, tmp, l, mid) + merge(a, tmp, mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while (i <= mid && j <= r) {
      if (a <= a) tmp = a;
      else {
            tmp = a;
            cnt += mid - i + 1;
      }
    }
    while (i <= mid) tmp = a;
    while (j <= r) tmp = a;
    for (i = l; i <= r; i++) a = tmp;
    return cnt;
}

int main() {
    int n;
    scanf("%d", &n);
    int *a = (int*)malloc((n + 1) * sizeof(int));
    for (int i = 1; i <= n; i++) {
      scanf("%d", &a);
      if (a % 2 != i % 2) {
            printf("-1\n");
            free(a);
            return 0;
      }
    }
    int *odd = (int*)malloc((n / 2 + 2) * sizeof(int));
    int *even = (int*)malloc((n / 2 + 2) * sizeof(int));
    int oc = 0, ec = 0;
    for (int i = 1; i <= n; i++) {
      if (i % 2 == 1) odd = a;
      else even = a;
    }
    int *tmp = (int*)malloc((n + 1) * sizeof(int));
    long long ans = merge(odd, tmp, 0, oc - 1) + merge(even, tmp, 0, ec - 1);
    printf("%lld\n", ans);
    free(a); free(odd); free(even); free(tmp);
    return 0;
}


如果你的 N 很小,也可以分别对 odd 和 even 写冒泡统计逆序数,但要注意只比较同一序列内的相邻元素。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 这个冒泡到底哪里有问题