離散化及其寫法

2022-03-20 05:08:03 字數 2422 閱讀 8653

離散化是演算法競賽中常常要用到的一種技巧,經常會出現在一些資料結構的題目中,和一些資料結構結合起來。試想,假如你現在看到了一道線段樹的裸題,在你極其興奮的同時發現資料範圍是1-1e10的,開4倍的線段樹根本開不下。於是你極其懊惱地只拿了部分分,可能還會因為心情不好而出鍋爆零(逃)...

所以這裡來講一下離散化的原理及實現方式(嚴肅)

ps:對於離散化零概念同學,建議從頭翻到尾,如果只是來複習離散化的寫法,請直接到文尾。

首先,什麼是離散化?

在鄙人的理解中,離散化就是比相對大小

為了本篇題解的正規性和學術性,先來貼一波標準定義:(滑稽)

離散化,把無限空間中有限的個體對映到有限的空間中去,以此提高演算法的時空效率。

通俗的說,離散化是在不改變資料相對大小的條件下,對資料進行相應的縮小。

看不懂就看下面的例子:

原數:131021 546412 973324

離散化後資料:1 2 3

夠形象了吧......

試想,當你要對乙個長度為\(10^\)的序列進行處理,你是否會開乙個如此之大的陣列?

除非你想mle,或者,你不會離散化。

在一些題目和演算法中,我們會發現,我們實現我們的想法的時候,只跟原資料的相對大小有關,比如1000000 和 2000000,在實際實現的時候,和1 2的效果是完全一樣的。那麼,開2000000那麼大的空間純屬浪費。那麼我們就用離散化給它對映到乙個較小的區間中。

通俗地來講,當有些資料本身很大, 自身無法作為陣列的下標儲存對應的屬性。如果這時只是需要這堆資料的相對屬性, 那麼可以對其進行離散化處理。當資料只與它們之間的相對大小有關,而與具體是多少無關時,可以進行離散化。

離散化的實現比較簡單。我們只需要維護兩個事情不變:首先:保證離散化之後的資料盡可能地小而且非負。其次:離散後的資料要保持原本的大小關係,原本相等的也要保持相等,否則就是錯誤的離散。

因此,找出原資料在序列中的序位就是離散化的關鍵。

我們在正常實現離散化的時候,有兩種方法

結構體實現:

**:

struct node

a[maxn];

int rank[maxn],n;

-----------------------------

for(int i=1;i<=n;i++)

sort(a+1,a+n+1);//從小到大

for(int i=1;i<=n;i++)

rank[num[i].id]=i;//對映

解釋:

這實際上就是乙個結構體模擬對映的過程。

一開始輸入了原資料,並且按次序儲存了id,也就是原數列的位置。

然後進行排序,易知對映後的資料範圍就是1-n。所以排序後的位置就放上我們當前的i即可。

但是,這個方式有乙個弊端,就是不能處理資料相等的情況。如果碰到資料相等,那麼離散化之後就變成了不等。

陣列實現

**:

int a[maxn],b[maxn];

for(int i=1;i<=n;i++)

sort(b+1,b+n+1,cmp);//cmp函式是自定義比較從小到大或從大到小的

int size=unique(b+1,b+n+1)-(b+1);

for(int i=1;i<=n;i++)

a[i]=lower_bound(b+1,b+size+1,a[i])-b;

解釋:

陣列實現離散化的碼量很少,減少了程式設計的複雜度。但是稍稍難理解一些(可能對讀者理解造成主要困難的就是不明白unique和lower-bound函式)。輸入a[i]之後緊接著儲存同樣的b[i]作為副本。然後對副本b進行去重,並儲存b陣列去重後的長度(size)。

然後開始離散化,直接把對應元素轉換成相應的陣列下標即可。

對unique和lower_bound函式不明白的同學請看下面:

針對上面那段**,已經被排好序的b陣列的下標就是我們要對映到的東西,我們就得到了乙個經過離散化之後的,去重的a陣列。

補充(upd:2020.3.16):也有一種寫法,是每次需要用a[i]的離散後數值時才查詢;個人不推薦這麼寫,因為當詢問次數很多的時候會大量消耗時間,而像上文那樣直接處理好的寫法,每次只需要o(1)的時間就可以完成查詢。

stl map實現(upd:2020.3.16)

stl為我們提供了乙個非常好的,可以處理對映問題的模板:map。

關於map容器,有不懂的小夥伴可以去翻:c++stl——map

模板:int a[maxn];

for(int i=1;i<=n;i++)

scanf("%d",&a[i]);

sort(a+1,a+n+1,cmp);

int cnt=0;

for(int i=1;i<=n;i++)

思想是一樣的,應用了乙個cnt變數來維護去重,呼叫的時候可以直接用鍵值,非常舒服方便。

校門外的樹(離散化寫法)

某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸0的位置,另一端在l的位置 數軸上的每個整數點,即0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起始點和終止...

資料離散化及其KMeans演算法實現的理論理解

k means演算法小結 資料離散化是資料預處理的乙個非常重要的步驟,就是將連續的資料分成幾個段。舉個簡單例子,好比我們乙個班上的學生成績是從0 100分之間的,但是我們在進行資料分析的時候呢我們把這些分數分成不及格 及格 良好 優秀四大類,實際上就是將比較連續的分數給離散化成了4種可能取值。那這樣...

離散化問題

題目傳送 uvalive 4127 the sky is the limit 大白書離散化簡單題。找了半天錯誤,居然是少輸出乙個空行。頓時感覺自己萌萌噠。其中計算幾何是套的之前留下的模板。ac include include include include include include inclu...