zoukankan      html  css  js  c++  java
  • LightHouse/归并排序

    灯塔(LightHouse)

    题目见https://dsa.cs.tsinghua.edu.cn/oj/problem.shtml?id=1144
    最近复习DSA,便在看邓老师的mooc,顺便做做配套的题目,挺有意思的。

    一、题目分析

    简述思路:两次排序,第一次是对结构体的x坐标进行排序,第二次是计数y坐标中的逆序对/顺序对的数目。
    第一次排序可以采用快速排序/归并排序等
    第二次就是归并排序计算逆序对数目

    注意点如下:

    • 数据范围大小,合适的地方需要使用long long,注意n*n结果范围可能超过int,此时也需要long long n;
    • new和delete需要配合使用。int* B=new int[lenB];...delete[] B;否则会造成内存泄漏,oj显示MLE
    • 归并排序的归并部分写法,最优写法如下
    for(int i=0,j=0,k=0;i<lenB;){
      if(j>=lenC||B[i]<C[j]){
        A[k++]=B[i++];
        if(j<lenC)count+=(lenC-j);//顺序对在这里出现
      }
      if(j< lenC&&C[j]<=B[i]){
        A[k++]=C[j++];//这里其实是逆序对
      }
    }
    
    • 逆序对计数在归并过程中自然进行即可,无需提前对B/C数组做二分查找。

    二、代码实现

    #include<cstdio>
    #define MAX_NUM 4000006
    typedef long long ll;
    struct point{
      int x;
      int y;
    };
    
    point origin[MAX_NUM];
    int arr[MAX_NUM];
    ll count;//顺序对数目
    
    void MergeSort_X(point* p,int lo,int hi);
    void MergeSort_Y(int* p,int lo,int hi);
    void Merge_X(point* p,int lo,int mi,int hi);
    void Merge_Y(int* p,int lo,int mi,int hi);
    
    int main(){
      int n;
      scanf("%d",&n );
      for(int i=0;i<n;i++){
        scanf("%d%d", &origin[i].x,&origin[i].y);
      }
      MergeSort_X(origin,0,n);//将origin数组按照X坐标升序排列
      for(int i=0;i<n;i++){
        arr[i]=origin[i].y;
      }
      MergeSort_Y(arr,0,n);//计算Y坐标中顺序对的数目
      printf("%lld",count);
    }
    
    //对数组p[lo,mi)按X坐标进行升序排序
    void MergeSort_X(point* p,int lo,int hi){
      if(hi-lo<2)return;
      int mi=(lo+hi)/2;
      MergeSort_X(p,lo,mi);
      MergeSort_X(p,mi,hi);
      Merge_X(p,lo,mi,hi);
    }
    
    //对数组p[lo,mi)和数组p[mi,hi)进行归并
    void Merge_X(point* p,int lo,int mi,int hi){
      point* A=p+lo;
      int lenB=mi-lo;//p[lo,mi)
      int lenC=hi-mi;//p[mi,hi)
      point* B=new point[lenB];
      for(int i=0;i<lenB;i++){
        B[i]=A[i];
      }
      point* C=p+mi;
      for(int i=0,j=0,k=0;i<lenB;){
        if(j>=lenC||B[i].x<=C[j].x)A[k++]=B[i++];
        if(j< lenC&&C[j].x< B[i].x)A[k++]=C[j++];
      }
      delete[] B;
    }
    
    void MergeSort_Y(int* p,int lo,int hi){
      if(hi-lo<2)return;
      int mi=(lo+hi)/2;
      MergeSort_Y(p,lo,mi);
      MergeSort_Y(p,mi,hi);
      Merge_Y(p,lo,mi,hi);
    }
    
    void Merge_Y(int* p,int lo,int mi,int hi){
      int* A=p+lo;
      int lenB=mi-lo;
      int lenC=hi-mi;
      int* B=new int[lenB];
      int* C=p+mi;
      for(int i=0;i<lenB;i++){
        B[i]=A[i];
      }
      for(int i=0,j=0,k=0;i<lenB;){
        if(j>=lenC||B[i]<C[j]){
          A[k++]=B[i++];
          if(j<lenC)count+=(lenC-j);//顺序对在这里出现
        }
        if(j< lenC&&C[j]<=B[i]){
          A[k++]=C[j++];//这里其实是逆序对
        }
      }
      delete[] B;
    }
    
  • 相关阅读:
    LeetCode 773. Sliding Puzzle
    oracle latch工作原理
    Oracle关于锁的几种类型和参数
    Java的反射机制
    JAVA多线程与并发学习总结
    Spring 概念详解
    Spring的AOP
    spring面试题 对DI , AOP概念的理解
    双11的架构
    Java线程的定义
  • 原文地址:https://www.cnblogs.com/cbw052/p/10467246.html
Copyright © 2011-2022 走看看