逆序对计算的思考 (Tsinghua OJ,PA1)
来源:互联网 发布:c语言判断奇数偶数 编辑:程序博客网 时间:2024/05/06 12:59
Tags:Blog
题目出自清华DSA的Programming Assignment作业灯塔(LightHouse).
描述
海上有许多灯塔,为过路船只照明。
如图一所示,每个灯塔都配有一盏探照灯,照亮其东北、西南两个对顶的直角区域。探照灯的功率之大,足以覆盖任何距离。灯塔本身是如此之小,可以假定它们不会彼此遮挡。
若灯塔A、B均在对方的照亮范围内,则称它们能够照亮彼此。比如在图二的实例中,蓝、红灯塔可照亮彼此,蓝、绿灯塔则不是,红、绿灯塔也不是。
现在,对于任何一组给定的灯塔,请计算出其中有多少对灯塔能够照亮彼此。
输入
共n+1行。
第1行为1个整数n,表示灯塔的总数。
第2到n+1行每行包含2个整数x, y,分别表示各灯塔的横、纵坐标。
输出
1个整数,表示可照亮彼此的灯塔对的数量。
样例
Input:
3
2 2
4 3
5 1
Output:
1
限制
对于90%的测例:1 ≤ n ≤ 3×10 5
对于95%的测例:1 ≤ n ≤ 10 6
全部测例:1 ≤ n ≤ 4×10 6
灯塔的坐标x, y是整数,且不同灯塔的x, y坐标均互异
1 ≤ x, y ≤ 10^8
时间:2 sec
内存:256 MB
提示
注意机器中整型变量的范围,C/C++中的int类型通常被编译成32位整数,其范围为[-231, 231 - 1],不一定足够容纳本题的输出。
思考
我们把灯塔坐标抽象为坐标结构体 typedef struct pos{ long x,y; }Pos;
照亮的情况为一个灯塔在另一个灯塔的一四象限,即
思路一:通过检测每个元素和其他元素的配对情况解决.简单计算知时间复杂度
思路二:利用二维线段树求解 暂不详解@XJSoft
思路三:利用逆序对求解.
具体思路为先对X坐标排序,则排好序的数组中一定有
只要统计Y坐标中前面的元素Y坐标比后面的元素小的即可.则不难得到
如图,X已经排好序,Y坐标为{2,1,3,4} 逆序对数量为1+0+0+0=1
总对数N(N - 1)对,其中不可照亮的有1对,可照亮的有N(N - 1) - 1 = 5对.
代码实现
经过多次优化,把
//CopyRight by XJSoft & ChestnutHeng.#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <math.h>#include <sys/time.h>#include <ctype.h>//#define DBG_FLAG //检测用时#define ISDIGIT(ch) (ch >= '0' && ch <= '9')long long detect;long long start_time;typedef struct pos //灯塔结构体{ long x,y; }Pos;typedef struct parser_ { //解释器,用于快速IO char *buf; int pos;} Parser;void read_line(Parser *parser, char *buffer) { gets(buffer); parser->buf = buffer; parser->pos = 0;}void read_all(Parser *parser, char *buffer) { long sz = 0; long readed;repeat: readed = fread(buffer + sz, 1, 100*1024*1024, stdin); //100M的缓冲区,一次读完数据 if (readed == 0) { buffer[sz] = '\0'; goto final; } sz += readed; goto repeat;final: parser->buf = buffer; parser->pos = 0;}inline long parse_long(Parser *parser) { while(!(ISDIGIT(parser->buf[parser->pos]) || parser->buf[parser->pos] == '-')) { parser->pos++; } long ret = 0; int sign = 0; if (parser->buf[parser->pos] == '-') { sign = 1; parser->pos++; } while(ISDIGIT(parser->buf[parser->pos])) { ret = ret * 10 + (parser->buf[parser->pos] - '0'); parser->pos++; } if (sign) { return -ret; } return ret;}Pos *temp;inline int compare(const void *p1, const void *p2) { //本来在Qsort中用的比较函数 return (*(Pos*)p1).x - (*(Pos*)p2).x;}long get_tick_count() {#ifdef DBG_FLAG struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000;#else return 0;#endif}long read_long() { long ret = 0; while(1) { int ch = fgetc(stdin); if (isdigit(ch)) { ungetc(ch, stdin); break; } } while(1) { int ch = fgetc(stdin); if (isdigit(ch)) { ret = ret * 10 + (ch - '0'); } else { return ret; } }}void debug_time(const char *msg) {#ifdef DBG_FLAG FILE *fp = fopen("time.log", "a"); fprintf(fp, "[%lld] %s\n", get_tick_count() - start_time, msg); fclose(fp);#endif}inline long merge(Pos *array,int low,int mid,int high){ int i = low,j = mid+1,k = low; long count = 0; while(i <= mid && j <= high) if(array[i].y <= array[j].y) { temp[k++] = array[i++]; } else{ temp[k++] = array[j++]; count += j-k; //逆序数计算 } while(i <= mid) temp[k++] = array[i++]; while(j <= high) temp[k++] = array[j++]; long long st = get_tick_count(); memcpy(array + low, temp + low, (high - low + 1) * sizeof(Pos)); //复制数组的优化 detect += (get_tick_count() - st); return count;}long mergeSort(Pos *array,int lo,int hi){ if(lo<hi) { int mid=(lo+hi)>>1; long count=0; count += mergeSort(array,lo,mid); count += mergeSort(array,mid+1,hi); count += merge(array,lo,mid,hi); return count; } return 0;}void QuickSort(Pos *data, int low, int high) { //手写快排的优化 if (low >= high) { return; } int pivot_item = low + rand() % (high - low + 1); Pos swp; swp = data[pivot_item]; data[pivot_item] = data[high]; data[high] = swp; Pos pivot = data[high]; int i, j; i = low; for (j = low; j < high; ++j) { if (data[j].x <= pivot.x) { swp = data[i]; data[i] = data[j]; data[j] = swp; i++; } } swp = data[i]; data[i] = data[high]; data[high] = swp; QuickSort(data, low, i - 1); QuickSort(data, i + 1, high);}int main(){ srand(time(NULL)); detect = 0; start_time = get_tick_count(); Pos * data = (Pos *)malloc(sizeof(Pos)*4000099); //数据区 debug_time("ALLOC."); int i; int t = 0; long n = 0; long ms; char *all_buf; all_buf = (char*)malloc(100*1024*1024); //缓冲区 Parser parser; read_all(&parser, all_buf); debug_time("RALL."); n = parse_long(&parser); Pos *pointer, *pend = data + n; for (pointer = data; pointer != pend; ++pointer) { //用解释器读取数据 pointer->x = parse_long(&parser); pointer->y = parse_long(&parser); } free(all_buf); debug_time("READ."); QuickSort(data, 0, n - 1); // qsort(data,n,sizeof(Pos),compare);#ifdef DBG_FLAG FILE *opt = fopen("sorted.txt", "w"); for (pointer = data; pointer != pend; ++pointer) { fprintf(opt, "%ld %ld\n", pointer->x, pointer->y); } fclose(opt);#endif debug_time("SORT."); temp = (Pos *)malloc(sizeof(Pos)*4000099); ms = n*(n-1)/2 - mergeSort(data,0,n - 1); printf("%ld\n",ms);#ifdef DBG_FLAG printf("%lld\n", detect);#endif debug_time("MERGE."); free(data); free(temp); debug_time("ENDED."); return 0;}
- 逆序对计算的思考 (Tsinghua OJ,PA1)
- 计算逆序对的个数
- Tsinghua OJ:祖玛(Zuma)
- Tsinghua OJ:灯塔(LightHouse)
- Tsinghua OJ:隧道(Tunel)
- 用mergesort计算逆序对的算法
- 归并排序--逆序数对的计算
- C++计算逆序对
- 计算逆序数对
- 计算逆序对
- C++计算逆序对
- THU-OJ-"PA1-2"-"Zuma Issue"
- 逆序对及其变种问题的一点思考
- Tsinghua OJ:范围查询(Range)
- Tsinghua OJ:列车调度(Train)
- Tsinghua OJ 多米诺骨牌(domino)
- 数组中的逆序对计算
- 逆序对计算(NLOG(N))
- Mysql设计与开发规范
- 第4周项目6-多项式求和
- 移动铁通宽带上网设置教程
- 584C
- Bootstrap CSS——页头与缩略图
- 逆序对计算的思考 (Tsinghua OJ,PA1)
- 努力
- spring学习之注入对象
- mysql 数据库 操作 获取某一个表的所有信息 主键 外键 类型
- AFNetWorking & ASI
- MySQL索引 查看、创建、删除
- Java基础编程3:水仙花数
- 建立索引所需要关注的问题
- IOS开发:CoreData的应用