有些数据很大无法作为数组的下标,这个问题已经让我碰到过许多次了,现在来整理一下离散化
离散化
离散化是指一些数据只需要知道它们之间的相对大小,与本身的大小的多少无关
如:对99999999,99999,1,23453,888892这五个数字,数据之间相差较大,且对于第一个数字用数组也无法用下标表示,所以就要将数组离散化,需要相对大小就可。这五个数字离散后为5,3,1,2,4
对重复元素进行离散化
代码一:
1 | #include<stdio.h> |
这个代码对上面五个数字进行离散化后的结果是4,2,0,1,3
代码二:
1 | #include<stdio.h> |
这个代码所得到的结果是5,3,1,2,4
区别:使用的二分函数不同
unique是“去掉”容器中相邻的重复元素(不一定要求数组有序),这里的去掉是将重复元素添加到容器的末尾(因此数组大小没有改变),返回的是去重后的尾地址。想要得到去重后的数组大小,就需要减去初始地址。
对无重复元素进行离散化
这种方法是用结构体储存原来元素的位置,排序之后重新赋值,
1 | #include<stdio.h> |
在这段代码中,结构体中有段注释部分的作用与我写的cmp函数一样,为什么要在结构体中写成那样目前我也不太明白。
样例:
INPUT
5
9999 999 99 9 1
输出
1 9 99 999 9999
由两种输入与输出的结果看,就可以看出两种离散化的不同了。
样例
西安邮电大学第五届ACM-ICPC校赛(同步赛)——G题——校车
- 题目描述
西安邮电大学有一辆从老校区到新校区的校车,总共有 n 个学生乘坐校车,在ai站上车,在bi站下车。学校打算去除一部分不必要的站点,请问需要保留多少站点,需要安排多少个座位? - 输入描述
输入 T 组数据 (1≤T≤10)
输入 n (1≤n≤1e5)
输入 n 组 ai,bi(1 ≤ ai < bi ≤ 1e9) - 输出描述
输出保留站点数,座位数。 - 示例一:
输入:
1
3
1 2
1 3
2 4
输出:
4 2 - 解题思路
把输入的站点排序离散化得出站点数,然后利用离散后的相对大小,去求站数的上车人数和下车人数。 - 解体代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
struct node{
long long x,y;
}a[100005];
long long b[200005];//离散后数组
long long c[100005];
int cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
int t;
int n,i,j;
scanf("%d",&t);
while(t--)
{
int cnt=0;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%lld%lld",&a[i].x,&a[i].y);
b[cnt++]=a[i].x;
b[cnt++]=a[i].y;
}
sort(a,a+n,cmp);
sort(b,b+cnt);
cnt=unique(b,b+cnt)-b;//离散后的数组大小
memset(c,0,sizeof(c));
int sum=1,ans=1;
int h;
h=lower_bound(b,b+cnt,a[0].y)-b+1;//把c的下标从1开始表示,表示第一站
c[h]++;
for(i=1;i<n;i++)
{
if(a[i].x==a[i-1].x)
{
ans++;
h=lower_bound(b,b+cnt,a[i].y)-b+1;
c[h]++;
}
else
{
h=lower_bound(b,b+cnt,a[i].x)-b+1;
ans++;
for(j=1;j<=h;j++)//该出站的人
{
ans=ans-c[j];
c[j]=0;
}
h=lower_bound(b,b+cnt,a[i].y)-b+1;
c[h]++;
}
sum=max(sum,ans);
}
printf("%d %d\n",cnt,sum);
}
return 0;
}