冒泡排序的交换次数

题意:

给定一个1~n的排列a0,a1,…an-1,求对这个数列进行冒泡排序所需要的交换次数(冒泡排序是每次找到满足ai>ai+1的i,并交换ai和ai+1,直到这样的i不存在为止的算法)。

限制条件:1<= n<= 100000

输入:

n=4, a={3,1,4,2}

输出:

3

冒泡排序的复杂度是O(n2),所有无法通过模拟冒泡排序的过程来计算需要的交换次数。不过我们可以通过选取适当的数据结构来解决这个问题。

首先,所求的交换次数等价于满足i<j,ai>aj的(i,j)数对的个数(这种数对的个数叫做逆序数)。而对于每一个j,如果能够快速求出满足i<j,ai>aj的i的个数,那么问题就迎刃而解。我们构建一个值得范围是1~n的BIT,按照j=0,1,2,…,n-1的顺序进行如下操作。

*把j-(BIT查询得到的前aj项的和)加到答案中

*把BIT中aj位置上的值加1

对于每一个j,(BIT查询得到的前aj项的和)就是满足i<j,ai<=aj的i的个数。因此把这个值从j中减去之后,得到的就是满足i<j,ai>aj的i的个数。由于对于每一个j的复杂度是O(logn),所以整个算法的复杂度是O(nlogn)。

#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;

int n;
int a[maxn];
int bit[maxn];

int sum(int i)
{
    int s = 0;
    while (i > 0){
        s += bit[i];
        i -= i & -i;
    }
    return s;
}

void add(int i, int x)
{
    while (i <= n){
        bit[i] += x;
        i += i & -i;
    }
}

void solve()
{
    ll ans = 0;
    for (int j = 0; j < n; j++){
        ans += j - sum(a[j]);
        add(a[j], 1);
    }
    printf("%lld\n", ans);
}
int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i++){
        scanf("%d", &a[i]);
    }
    solve();
    return 0;
}
时间: 2024-11-04 12:17:46

冒泡排序的交换次数的相关文章

冒泡排序的交换次数 (树状数组)

计算冒泡排序的交换次数: 逆序数概念:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序 一个排列中所有逆序总数叫做这个排列的逆序数. 所以冒泡排序结束即是所有的逆序数为0 思路: 暴力:我们可以开一个vis[]数组记录 在遍历到第 i 位时,已经出现的值有哪些.然后遍历到 arr[i] (第i位的值),得到小于arr[i] 的出现个数(即 i<j && arr[i]<= arr[j]的个数) 然后再用当前长度 i 减去符合条件个数

UVA 299- Train Swapping(冒泡排序中交换次数)

Train Swapping Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description  Train Swapping  At an old railway station, you may still encounter one of the last remaining ``train swappers''. A train swapper is an em

【算法28】冒泡排序中的交换次数问题

问题描述 题目来源:Topcoder SRM 627 Div2 BubbleSortWithReversals 给定待排序数组A,在最多反转K个A的不相交子数组后,对A采用冒泡排序,问最小的swap次数是多少?冒泡排序的伪代码如下: BubbleSort(A): 循环len(A) - 1次: for i from 0 to len(A) - 2: if (A[i] > A[i+1]) swap(A[i], A[i+1]) 问题分析 首先,容易分析得到:对于任意待排序数组A,其采用冒泡排序所需要的

POJ 2299-Ultra-QuickSort(归并排序求相邻元素的交换次数)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 43816   Accepted: 15979 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

Cycle Sort (交换次数最少的排序)

该算法的效率并不高.但是却提供了一个很好的思路.如何让一个序列在最小交换次数下实现有序. Cycle Sort 翻译成中文是 圈排序. 这个圈在于需要交换的数据形成圈. 具体一点: 如: Array  4 3 2 5 5 6  要处理的数组 Result 2 3 4 5 5 6  结果 pos     0 1 2 3 4 5  下标 从下标0的元素开始观察.4 需要到下标 2 而下标2的元素为 2 需要到下标0 .刚好可以回到4. 也就是形成了 4-2 这样的圈 接下来是3 需要到下标1 而3本

neu 1493 Caoshen like math(最小交换次数)

http://acm.neu.edu.cn/hustoj/problem.php?cid=1047&pid=4 题意:数字1到n 任意排列 求排列成有序序列最少交换次数 思路:求最小交换次数有两种 1 交换的两数必须相邻  (poj 2299) 通过归并排序求出其逆序数即为所求值 证明:可以先将最大数交换到最后,由于是相邻两个数交换,需要交换的次数为最大数后面的数的个数(可以看做是最大数的逆序数),然后,交换过后,去除最大数,再考虑当前最大数也需要其逆序数次交换.则每个数都需要交换其逆序数次操作

关于一个求最小交换次数的算法的一个严格证明,是严格证明,不是想当然

问题描述: 有一个1~n的数列的排列,但是这个数列已经被打乱了排列顺序,如果我们只是通过"交换任意两个元素",那么,要实现元素从1~n的有序排列,"最少的交换次数是多少?" 解答过程: 首先我们纸上可以先写写简单的情况试试,比如排列:4 3 1 2, 交换次数=3:我们可以在多组测试中,边测试边想,真正的实现需要满足:4本该到2处, 2本该到3处, 3本该到1处, 1本该到4处,刚好一个循环. 于是,考虑: 引理:是否对于满足这种一个循环的排列,最少交换次数等于元素

Baidu笔试-01序列排序的交换次数

问题描述: 问题分析: 解法一:设置双指针,start,end;当data[start]='1',data[end]='0'时,表示需要进行交换,次数加1:否则data[end]='1'则前移end指针:data[start]='0'则后移start指针: 该算法仅需遍历一次 解法二:先遍历一次计算字符数组中0的个数zero,再计算前zero个字符中1的个数,即是要交换到后面的字符(仅需遍历到zero个字符即可): 代码: 解法一: import java.util.Scanner; publi

让冒泡排序的对比次数更少(js实例)

一般网上的冒泡排序例子是这样的: function bubbleSort(arr) { let i = arr.length; let tempExchangVal = undefined; while (i > 0) { for (let j = 0; j < i - 1; j++) { num++; if (arr[j] > arr[j + 1]) { tempExchangVal = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = tempExc