zoukankan      html  css  js  c++  java
  • 归并排序,树状数组 两种方法求逆序对

    我们知道,求逆序对最典型的方法就是树状数组,可是另一种方法就是Merge_sort(),即归并排序。


    实际上归并排序的交换次数就是这个数组的逆序对个数,为什么呢?


    我们能够这样考虑:


    归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。

    在合并的过程中(设l<=i<=mid,mid+1<=j<=h)。当a[i]<=a[j]时。并不产生逆序数;当a[i]>a[j]时。在

    前半部分比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话。逆序数要加上mid+1-i。

    因此,能够在归并

    序中的合并过程中计算逆序数.


    题目:http://poj.org/problem?

    id=1804


    题意:给定一个序列a[],每次仅仅同意交换相邻两个数,最少要交换多少次才干把它变成非递降序列.

    #include <iostream>
    #include <string.h>
    #include <stdio.h>
    
    using namespace std;
    const int N = 1005;
    
    int a[N],tmp[N];
    int ans;
    
    void Merge(int l,int m,int r)
    {
        int i = l;
        int j = m + 1;
        int k = l;
        while(i <= m && j <= r)
        {
            if(a[i] > a[j])
            {
                tmp[k++] = a[j++];
                ans += m - i + 1;
            }
            else
            {
                tmp[k++] = a[i++];
            }
        }
        while(i <= m) tmp[k++] = a[i++];
        while(j <= r) tmp[k++] = a[j++];
        for(int i=l;i<=r;i++)
            a[i] = tmp[i];
    }
    
    void Merge_sort(int l,int r)
    {
        if(l < r)
        {
            int m = (l + r) >> 1;
            Merge_sort(l,m);
            Merge_sort(m+1,r);
            Merge(l,m,r);
        }
    }
    
    int main()
    {
        int n,T,tt=1;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            for(int i=0;i<n;i++)
                scanf("%d",&a[i]);
            ans = 0;
            Merge_sort(0,n-1);
            printf("Scenario #%d:
    %d
    
    ",tt++,ans);
        }
        return 0;
    }
    

    树状数组求逆序:


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

    思路: 离散化+树状数组
    分析:
    1 题目的意思就是要求逆序数对
    2 题目的输入个数有500000的规模可是每一个数的最大值为999999999。因此我们须要离散化这些数据
    3 对于数据9 1 0 5 4我们离散化成5 2 1 4 3
    那么对于输入一个树a[i]我们去求一下它的离散化后的id,然后去求前面比这个id大的个数
    4 因为getSum(x)函数的求和是求[1,x]而不是[x。MAXN),所以我们能够换成求小于等于id的个数即getSum(id),然后i-1-getSum(id)就是比id大的个数,最后在更新一下treeNum[id]

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int MAXN = 500010;
    
    int n;
    int tmpNum[MAXN] , num[MAXN];
    int treeNum[MAXN];
    
    int lowbit(int x){
        return x&(-x);
    }
    
    int getSum(int x){
        int sum = 0;
        while(x){
            sum += treeNum[x];
            x -= lowbit(x);
        }
        return sum;
    }
    
    void add(int x , int val){
        while(x < MAXN){
             treeNum[x] += val;
             x += lowbit(x);
        }
    }
    
    long long solve(){
        long long ans = 0;
        memcpy(tmpNum , num , sizeof(num));
        memset(treeNum , 0 , sizeof(treeNum));
        sort(num+1 , num+1+n);
        int len = unique(num+1 , num+1+n)-(num+1);
        for(int i = 1 ; i <= n ; i++){
            int id = lower_bound(num+1 , num+1+n,tmpNum[i])-num;
            ans += i-getSum(id)-1;
            add(id , 1);
        }
        return ans;
    }
    
    int main(){
        while(scanf("%d" , &n) && n){
             for(int i = 1 ; i <= n ; i++)
                 scanf("%d" , &num[i]);
             printf("%lld
    " , solve());
        }
        return 0;
    }
    


  • 相关阅读:
    关于vue 自定义组件的写法与用法
    常用的几种监控服务器性能的Linux命令
    Web自动化测试入门
    接口测试入门
    Selenium+IDEA(java+maven+testNG)+Jenkins环境搭建
    Jmeter+ant+Jenkins环境搭建
    iframe在移动端的缩放
    CSS3的颜色渐变效果
    Hexo建博小结
    Ajax基本概念和原理
  • 原文地址:https://www.cnblogs.com/clnchanpin/p/6935213.html
Copyright © 2011-2022 走看看