常用技巧 —— 离散化
【概述】
離散化是數據結構中的一個常用技巧,其可以有效的降低時空復雜度,其基本思想就是在眾多可能的情況中,只去考慮需要用到的值,通過離散化,可以改進低效的算法,甚至實現根本不可能實現的算法。
對于一些數量較少,但數值較大或者可能出現負數這種難以處理的數據,自身無法作為數組的下標保存對應的屬性,如果這時只是需要這些數據的相對屬性, 那么可以對其進行重新賦值,即進行離散化處理。
簡單來說,對于 n 個數據,當 n 很小而每個數據 a[i] 的數據范圍很大時,就可以考慮離散化為更小的值,將他們重新賦值為 [1,n] 之間的數據,從而實現更多的算法。
例如:有 1E5 個數,每個數的大小不超過 1E9,要對這些數進行某些操作(并查集等),那么肯定不能直接開 1E9 大小的數組,但是 1E5 的范圍就完全沒問題,也就是說,當不需要這些數據具體是多少時,只需要知道他們的相對大小。
離散化分為兩種,一種是重復的元素離散化后數值仍相同,一種則是重復的元素離散化后數值不同。
【STL+二分實現離散化】
使用?STL+二分 實現離散化,重復的元素數值仍相同,其實質就是利用一個輔助數組將要離散的數據保存下來,然后進行排序去重,最后再用二分將離散數據的位置放回原數組。
注:
- 去重并不是將數組中重復的元素刪除,而是將重復的元素放在數組末尾
- 二分時,要注意二分的區間范圍一定是離散化后的區間
例如:對于數組 {6,8,4,9,5,6,7,4},在排序后得到 {4,4,5,6,6,7,8,9},去重后得到 {4,5,6,7,8,9},經過二分后,原序列變為 {3,5,1,6,2,3,4,1}
int temp[N],a[N]; int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i];temp[i]=a[i];//輔助數組臨時存儲}sort(temp+1,temp+n+1);//排序,便于去重int len=unique(temp+1,temp+n+1)-temp-1;//去重,len為去重后數組長度for(int i=1;i<=n;i++)//a[i]即為離散化后的數組a[i]=lower_bound(temp+1,temp+len+1,a[i])-temp; }【用數組離散】
使用數組實現離散化,重復的元素數值不同,其直接用結構體存儲原序列元素的位置,經過排序后將他們重新賦值,最后將結果存放在 rank 數組中。
例如:
對于序列 {3,6,5,10,8},其初始值和 id 為:?
經過排序后:
進行離散化:
再按照原來的順序進行排列:
此時,rank 數組就是離散化后的值
struct Node{int val,id;bool operator < (const Node &rhs)const{//按值排序return val<rhs.val;} }a[N]; int rank[N];//離散化后的值 int main(){int n;cin>>n;for(int i=1;i<=n;i++){cin>>a[i].val;a[i].id=i;//記錄序號}sort(a+1,a+n+1);//按值排序for(int i=1;i<=n;i++)//進行映射rank[a[i].id]=i; }【例題】
- 程序自動分析(洛谷-P1955)(離散化+并查集):點擊這里
- Making the Grade(POJ-3666)(離散化思想+線性DP):點擊這里
- Mindis(HDU-6670)(離散化+網格圖建圖+bfs):點擊這里
- Parity game(POJ-1733)(離散化+帶權并查集區間問題):點擊這里
總結
以上是生活随笔為你收集整理的常用技巧 —— 离散化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 生日蛋糕(信息学奥赛一本通-T1441)
- 下一篇: 算术(HDU-6715)