• 求逆序数的方法--线段树法&归并排序法


    逆序数的概念:对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。

    解决思路:

    HDU-1394

    1、线段树:通过保存区间内数的出现次数,每次插入一个数前把比它小(大)的区间内的总数累加。

     1 //求逆序数 线段树法
     2 //原理,因为输入是依次输入的,所以每次输入一个数,只要查找比这个数小数的个数并累加就行了。
     3 //顺序查找的复杂度是O(n),很容易想到用线段树保存每个数的出现次数,每次输入在比他小(大)的区间中查找总数就行了
     4 #include <iostream>
     5 #define N 5010
     6 using namespace std;
     7 int tree[N<<2];//线段树保存了每个区间内数字出现总数
     8 void CreatTree(int node,int l,int r)
     9 {
    10     if(l==r)
    11     {
    12         tree[node]=0;
    13         return ;
    14     }
    15     int mid=(l+r)>>1;
    16     CreatTree(node<<1, l, mid);
    17     CreatTree(node<<1|1, mid+1, r);
    18     tree[node]=tree[node<<1]+tree[node<<1|1];
    19 }
    20 void Insert(int node,int num,int l,int r)
    21 {
    22     if(l==num&&r==l)
    23     {
    24         tree[node]++;
    25         return ;
    26     }
    27     int mid=(l+r)>>1;
    28     if(num<=mid)
    29         Insert(node<<1, num, l, mid);
    30     else
    31         Insert(node<<1|1, num, mid+1, r);
    32     tree[node]=tree[node<<1]+tree[node<<1|1];
    33 }
    34 int Query(int node,int ql,int qr,int l,int r)
    35 {
    36     if(qr<ql)
    37         return 0;
    38     if(ql<=l&&r<=qr)
    39         return tree[node];
    40     int mid=(l+r)>>1;
    41     int rec=0;
    42     if(ql<=mid)
    43         rec+=Query(node<<1, ql, qr, l, mid);
    44     if(qr>mid)
    45         rec+=Query(node<<1|1, ql, qr, mid+1, r);
    46     return rec;
    47 }
    48 int main(int argc, const char * argv[]) {
    49     int n;
    50     while(cin>>n)
    51     {
    52         int ans=0,temp;
    53         int num[N];
    54         CreatTree(1, 0, n-1);
    55         for(int i=0;i<n;i++)
    56         {
    57             cin>>temp;
    58             num[i]=temp;
    59             Insert(1, temp, 0, n-1);
    60             ans+=Query(1, temp+1,n-1, 0, n-1);
    61         }
    62         int sum=ans;
    63         for(int i=0;i<n;i++)
    64         {
    65             ans=ans-num[i]+n-num[i]-1;
    66             if(ans<sum)
    67                 sum=ans;
    68         }
    69         cout<<sum<<endl;
    70     }
    71     return 0;
    72 }

    2、归并排序:归并排序过程中,如果左序列的第j个值大于有序列第k个值,那么j~lenl的值都大于k,所以每次ans+=

    id-(left+j)+1。完成整个归并排序,就可以统计所有逆序数对的数量。

     1 //求逆序数 归并排序法
     2 //在归并排序过程中,每次对左右两个有序数列排序时,如果左边序列的第j个值大于右边序列k个值
     3 //那么说明左边序列的j~lenl个值都大于第k个值,所以把其加到ans中
     4 #include <iostream>
     5 #define N 5010
     6 using namespace std;
     7 bool cmp(int a,int b)
     8 {
     9     return a<=b;
    10 }
    11 int ans;
    12 void MergeArr(int num[], int left, int mid, int right)
    13 {
    14     int AL[N], AR[N],lenl=mid-left+1,lenr=right-mid;
    15     for (int i = 0;i < lenl;i++)
    16         AL[i] = num[left + i];
    17     for (int i = 0;i < lenr;i++)
    18         AR[i] = num[mid + 1 + i];
    19     int j = 0, k = 0,pos=left;
    20     while (j < lenl&&k < lenr)
    21     {
    22         if (cmp(AL[j], AR[k]))
    23             num[pos++] = AL[j++];
    24         else
    25             num[pos++] = AR[k++],ans+=mid-(left+j)+1;//关键步骤
    26     }
    27     while (j < lenl)
    28         num[pos++] = AL[j++];
    29     while (k < lenr)
    30         num[pos++] = AR[k++];
    31 }
    32 void MergeSort(int num[], int left, int right)
    33 {
    34     if (left < right)
    35     {
    36         int mid = (right + left) / 2;
    37         MergeSort(num, left, mid);
    38         MergeSort(num, mid+1, right);
    39         MergeArr(num, left, mid, right);
    40     }
    41 }
    42 int main() {
    43     int n;
    44     while(cin>>n)
    45     {
    46         ans=0;
    47         int num[N],temp[N];
    48         for(int i=0;i<n;i++)
    49             cin>>num[i],temp[i]=num[i];
    50         MergeSort(temp, 0, n-1);
    51         int sum=ans;
    52         for(int i=0;i<n;i++)
    53         {
    54             ans=ans-num[i]+n-num[i]-1;
    55             if(ans<sum)
    56                 sum=ans;
    57         }
    58         cout<<sum<<endl;
    59     }
    60     return 0;
    61 }
  • 相关阅读:
    Window PHP 使用命令行模式
    LNMP ftp 可以登录无权限操作?
    linux 允许mysql用户远程访问
    解决报错:scandir() has been disabled for security reasons
    LNMP 配置二级域名
    MUI 图片上传剪切预览,可选(拍照+系统相册)
    MUI 单个图片上传预览(拍照+系统相册):先选择->预览->上传提交
    MUI 单图片压缩上传(拍照+系统相册): 选择立即上传
    循环递归的区别?
    如何让自己的广播只让指定的 app 接收?
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/5773309.html
Copyright © 2020-2023  润新知