归并排序的利用

归并排序可以用其O(nlgn)的速度解决很多问题,另外在其归并的过程中,还可以做一些小动作。

例如:求一系列点[1,3,8,4,.....]的逆序对数,或正序对数。(两两比较左小于右为正序)

然后,就有了《灯塔问题》这个题目。

/*  灯塔的坐标为(x,y),且各不相同,灯塔处于另外一个灯塔的东北角90度范围,或西南角90度范围内,才能互相照射到。

/*  给定N个(x,y)坐标,求能互相照射到的对数。(网上可以搜索到此题。)

Input

3
2 2
4 3
5 1

Output

1

解答:此题是在归并的基础上,利用正序对的数目来记录答案。首先根据x来排一次序,然后再对y排序时,小动作出现在merge的时候:
当左边那个要比较的点小于右边那个要比较的点,那左边那个点对应的正序对数目增加的个数为(右边剩余点的个数n2-j)
这个要分析透彻,不然很容易出错。(相同方式可以知道求逆序时:左边点大于右边点,逆序对+=n1-i)

  1 //@version: v2.0
  2 //@author: jackxu_cn
  3 
  4 #include<cstdio>
  5 //#define DEBUG
  6 
  7 typedef struct lighthouse_t{
  8     long x;
  9     long y;
 10 }LightHouse;
 11 
 12 void sort(long start, long end, bool rec);
 13 void merge(long start, long mid, long end, bool rec);
 14 
 15 
 16 long num=0;
 17 LightHouse* a;
 18 int main()
 19 {
 20     long n,i;
 21     scanf("%ld",&n);
 22     a= new LightHouse[n];
 23     for(i = 0; i < n; i++)
 24         scanf("%ld %ld",&a[i].x,&a[i].y);
 25 
 26     sort(0, n-1, false);
 27 #ifdef DEBUG
 28     for(i=0;i<n;i++)
 29         printf("---->%ld %ld\n",a[i].x,a[i].y);
 30 #endif
 31     sort(0, n-1, true);
 32 
 33 
 34     printf("%ld\n",num);
 35     return 0;
 36 }
 37 
 38 
 39 void sort(long start, long end, bool record)
 40 {
 41     if (start < end) {
 42         long mid = (start + end) >> 1;
 43         sort(start, mid, record);
 44         sort(mid+1, end, record);
 45         merge(start, mid, end, record);
 46     }
 47 }
 48 
 49 
 50 
 51 
 52 void merge(long start, long mid, long end, bool record)
 53 {
 54     long n1 = mid - start+1;
 55     long n2 = end - mid;//end-(mid+1)+1
 56     LightHouse *left=new LightHouse[n1];
 57     LightHouse *right=new LightHouse[n2];
 58     long i, j, k;
 59 
 60     for (i = 0; i < n1; i++) /* left holds a[start..mid] */
 61         left[i] = a[start+i];
 62     for (j = 0; j < n2; j++) /* right holds a[mid+1..end] */
 63         right[j] = a[mid+1+j];
 64 
 65     i = j = 0;
 66     if (record){
 67         for(k=start; k<=end; k++)
 68         {
 69             if(i>=n1 && j<n2)//left:0  right:>0
 70             {
 71                 a[k]=right[j++];
 72                 //num+=n1;
 73             }else if(i<n1 && j>=n2)//left:>0 right:0
 74             {
 75                 a[k]=left[i++];
 76             }else//left>0 right>0
 77             {
 78                 if (left[i].y <= right[j].y)     {a[k]= left[i++]; num+=n2-j;}
 79                 else                             {a[k]= right[j++];}
 80             }
 81         }
 82     }else
 83     {
 84         for(k=start; k<=end; k++)
 85         {
 86             if(i>=n1 && j<n2)//left:0  right:>0
 87             {
 88                 a[k]=right[j++];
 89             }else if(i<n1 && j>=n2)//left:>0 right:0
 90             {
 91                 a[k]=left[i++];
 92             }else//left>0 right>0
 93             {
 94                 if (left[i].x <= right[j].x)     a[k]= left[i++];
 95                 else                             a[k]= right[j++];
 96             }
 97         }
 98     }
 99     delete[] left;
100     delete[] right;
101 }
View Code

 

 
posted @ 2015-09-28 15:24  jack-xu  阅读(273)  评论(0编辑  收藏  举报