逆序数的求法

求一个数列的逆序数

逆序对:数列s[1],a[2],a[3]…中的任意两个数s[i],s[j] (i<j),如果s[i]>s[j],那么我们就说这两个数构成了一个逆序对

逆序数:一个数列中逆序对的总数

如数列 3 5 4 8 2 6 9

(5,4)是一个逆序对,同样还有(3,2),(5,2),(4,2)等等

那么如何求得一个数列的逆序数呢?

方法1:一个一个的数

最简单也是最容易想到的方法就是,对于数列中的每一个数s[i],遍历数列中的数s[j](其中j<i),若s[i]<s[j],则逆序数加1,这样就能统计出该数列的逆序数总和

该方法的时间复杂度为O(n2),具体过程就不细说了

代码如下:(POJ  1804 Brainman)

http://poj.org/problem?id=1804

/*直接求逆序数O(n^2)*/

//Memory Time
//220K  188MS

#include <iostream>
using namespace std;

int main(int i,int j)
{
    int test;
    cin>>test;
    for(int p=1;p<=test;p++)
    {
        int n;
        cin>>n;

        int* s=new int[n+1];
        for(i=1;i<=n;i++)
            cin>>s[i];

        int t=0;  //s[]的逆序数
        for(i=1;i<=n-1;i++)   //把S[i]和s[i+1~n]的元素逐个比较
            for(j=i+1;j<=n;j++)
                if(s[i]>s[j])  //如果s[i] > s[j] (j∈[i+1,n])
                    t++;   //则逆序数t++

        cout<<"Scenario #"<<p<<‘:‘<<endl<<t<<endl<<endl;

        delete s;
    }
    return 0;
}

方法2:归并的思想

有一种排序的方法是归并排序,归并排序的主要思想是将整个序列分成两部分,分别递归将这两部分排好序之后,再和并为一个有序的序列.复杂度为O(nlogn)算法

/*借助Mergesort求逆序数O(nlogn)*/

//Memory Time
//228K   172MS 

#include<iostream>
using namespace std;

const int inf=1000001;
int t;  //数字序列s[]的逆序数

void compute_t(int* s,int top,int mid,int end)
{
    int len1=mid-top+1;
    int len2=end-mid;

    int* left=new int[len1+2];
    int* right=new int[len2+2];

    int i,j;
    for(i=1;i<=len1;i++)
        left[i]=s[top+i-1];
    left[len1+1]=inf;

    for(j=1;j<=len2;j++)
        right[j]=s[mid+j];
    right[len2+1]=inf;

    i=j=1;
    for(int k=top;k<=end;k++)
        if(left[i]<=right[j])
            s[k]=left[i++];
        else
        {
            s[k]=right[j++];
            t+=len1-i+1;
        }

    delete left;
    delete right;

    return;
}

void mergesort(int* s,int top,int end)
{
    if(top<end)
    {
        int mid=(top+end)/2;
        mergesort(s,top,mid);
        mergesort(s,mid+1,end);
        compute_t(s,top,mid,end);
    }
    return;
}
int main(void)
{
    int test;
    cin>>test;
    for(int p=1;p<=test;p++)
    {
        int n;  //数字序列s[]长度
        cin>>n;

        int* s=new int[n+1];

        for(int i=1;i<=n;i++)
            cin>>s[i];

        t=0;
        mergesort(s,1,n);

        cout<<"Scenario #"<<p<<‘:‘<<endl<<t<<endl<<endl;

        delete s;
    }
    return 0;
}
时间: 2024-08-07 00:18:53

逆序数的求法的相关文章

逆序数的求法总结(归并、线段树、树状数组、离散化)

1.归并排序求逆序数 http://acm.nyist.net/JudgeOnline/problem.php?pid=117 在归并排序的过程中,比较关键的是通过递归,将两个已经排好序的数组合并,此时,若a[i] > a[j],则i到m之间的数都大于a[j],合并时a[j]插到了a[i]之前,此时也就产生的m-i+1个逆序数,而小于等于的情况并不会产生. 1 #include<stdio.h> 2 #define maxn 1000005 3 int a[maxn],temp[maxn

逆序数的几种求法

逆序数的几种求法 白话经典算法系列之九 从归并排序到数列的逆序数对(微软笔试题)

NYOJ117&amp;&amp; 树状数组求逆序数

(转)树状数组可以用来求逆序数, 当然一般用归并求.如果数据不是很大, 可以一个个插入到树状数组中, 每插入一个数, 统计比他小的数的个数,对应的逆序为 i- getsum( data[i] ),其中 i 为当前已经插入的数的个数, getsum( data[i] )为比 data[i] 小的数的个数i- sum( data[i] ) 即比 data[i] 大的个数, 即逆序的个数但如果数据比较大,就必须采用离散化方法.一关键字的离散化方法:所谓离散化也就是建立一个一对一的映射. 因为求逆序时只

拼图游戏中逆序数的实现的三种方式

一.定义 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.如2431中,21,43,41,31是逆序,逆序数是4. 二.计算方法 逆序数的计算方法主要有直接计算,归并和树状数组三种,下面将一一介绍. 2.1 直接计算 即根据定义用枚举的方法求逆序数.对于数列中的每一个数a[i],遍历数列中的数a[j] (其中j < i),若a[i] < a[j],则逆序数加1,这样就能统计出该数列的逆序数总和. 该方

POJ 2299 Ultra-QuickSort (归并排序求逆序数)

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

ACM ICPC 2011–2012, NEERC, Northern Subregional Contest J. John’s Inversions(合并排序求逆序数对数)

题目链接:http://codeforces.com/gym/100609/attachments 题目大意:有n张牌,每张牌有红色和蓝色两面,两面分别写了一些数字,同种颜色的任意两个数字若排在前面的数字比排在后面的数字大就叫做一对逆序数.求怎样排序得到的逆序数对最少. 解题思路:其中一种颜色的数字是顺序且这种颜色数字相同时对应的另一种颜色的数字是顺序时得到的逆序数对数最少.难点在于求逆序数对数.因为数量很大O(n^2)复杂度不能满足,这里根据合并排序的原理求解每个数字前面有多少个比它大的数字,

CSU 1555 Inversion Sequence 给出逆序数求排列 splay

题目链接:点击打开链接 题意: 给出逆序数的值,求原序列(一个1-N的排列) 1, 2, 0, 1, 0 表示1的逆序数是1,2的逆序数是2,3的逆序数是0··· 思路: 从最后一个数开始插,每次插到当前序列的第a[i]个数.. splay模拟 == 这个方法比较直(wu)观(nao),别的方法并没有想出来.. #include <cstdio> #include <iostream> #include <cstring> #include <queue>

1019 逆序数

1019 逆序数 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4.给出一个整数序列,求该序列的逆序数. Input 第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9) Ou

归并排序_逆序数

归并排序求逆序数 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数.一个排列中所有逆序总数叫做这个排列的逆序数.也就是说,对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序.一个排列中所有逆序总数叫做这个排列的逆序数. 1 #include<cstdio> 2 #in