归并排序可以用其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 }
时间: 2024-10-07 18:53:48