Trie樹 永遠不可能學會的動態規劃之狀壓DP

2021-08-22 09:52:05 字數 1962 閱讀 6255

時間限制: 1 sec  記憶體限制: 128 mb

提交: 195  解決: 46

[提交] [狀態] [討論版] [命題人:admin]

題目描述

字母(trie)樹是乙個表示乙個字串集合中所有字串的字首的資料結構,其有如下特徵:

1.樹的每一條邊表示字母表中的乙個字母

2.樹根表示乙個空的字首

3.樹上所有其他的節點都表示乙個非空前綴,每乙個節點表示的字首為樹

根到該節點的路徑上所有字母依次連線而成的字串。

4.乙個節點的所有出邊(節點到兒子節點的邊)中不存在重複的字母。

現在matej手上有n個英文小寫字母組成的單詞,他想知道,如果將這n個單詞中的字母分別進行重新排列,形成的字母樹的節點數最少是多少。

輸入第一行包含乙個正整數n(1<=n<=16)

接下來n行每行乙個單詞,每個單詞都由小寫字母組成。

單詞的總長度不超過1,000,000。

輸出輸出僅乙個正整數表示n個單詞經過重新排列後,字母樹的最少節點數。

樣例輸入

3aab

abc

樣例輸出

4
[提交] [狀態]

此題題目是trie,但是和trie沒有什麼太大關係,只需要知道,對於這些串,將他們的公共部分作為公共字首是最優的即可。

那麼首先考慮兩個串,答案顯然是他們的長度和減去公共部分。

那麼再考慮三個串,顯然可能出現兩兩的公共部分大於三個的公共部分的情況,這種時候trie樹必然會出現分叉,我們需要考慮如何分叉,分成二叉或三叉,再者哪些串在同一子樹上,既然一定會分成多顆子樹,那麼我們可以直接將這三個串拆成兩個子集,先求出兩個子集的最優解,然後減去公共部分即可。

也就是說,令f[s]f[s]表示將ss集合中的字串弄到一棵樹上的最少節點數,那麼有

f[s]=minf[k]+f[s xor k]−s中字串的公共部分長度f[s]=minf[k]+f[s xor k]−s中字串的公共部分長度

然後考慮dp[i] == sum的時候,說明此時的所有選擇的串都相同,也就不存在需要減去的情況,故只有當dp[i] > sum時,才需要dp[i]-sum。

最後需要結果+1.字典樹的根節點是空值。收穫:高效枚舉子狀態for(int j=i&i-1;j;j=i&j-1)

ps 一般 n<16是用狀壓dp的條件

設s表示乙個01狀態集,那麼它的所有非空子集x可以通過以下**列舉。

for (int x = s; x; x = (x-1)&s)
x = (x-1)&s實際上是把s中的0全部忽略,並不斷減1的結果,比如s=1011,則x分別為:1011, 1010, 1001, 1000, 0011, 0010, 0001。忽略s中第二位的0其實就是111, 110, 101, 100, 011, 010, 001。

稱s中的1所在位為有效位,0所在位為無效位,則x中的無效位必為0,有效位為0或1,比如s=1011,x=1001(有效位加下劃線)。-1就是加上-1補碼1111…,可以想成把無效位的1先加上去,比如x=1001變成1101,再加有效位的1。由於無效位加完肯定是1,會把有效位的進製「傳遞」下去,然後再位與s使得無效位變成0,實際就相當於有效位加上1111…,也就是有效位-1。

#include #include #include #include #include #include #include #include #include#include#define inf 0x3f3f3f3f

using namespace std;

int vis[20][30],len[30],ans[30];

char s[100005];

int dp[1<<16+5];

int n;

int main()

printf("%d\n",dp[(1<

return 0;

}

愛情永遠不可能是天平

愛情永遠不可能是天平。你想在愛情裡幸福就要捨得傷心。愛情原來本就是海浬的沙,只有你用心去呵護它,用淚和心血去滋潤它,讓它沉醉於心才能成為一顆水晶 人的精神有三種境界 駱駝 獅子和嬰兒。第一境界駱駝,忍辱負重,被動地聽命於別人或命運的安排 第二境界獅子,把被動變成主動,由 你應該 到 我要 一切由我主...

不是不可能的

今天在網上看到了四川的災情,已經有5萬5千多人遇難了,真的很難過,也真的很震撼,心理 突然萌生一種思想,我能為災區做什麼,我能做什麼,捐錢,我能捐多少啊,捐血我又能捐多 少啊,我是上帝的女兒,我能拯救這世人嗎,我能嗎,上帝已經給了我這責任,給了我,自從 上帝打算揀選我那天開始,我必須要做好,我要先從...

使用反射動態建立Enum 不可能

朋友有個難題,要動態建立列舉,google了一下,基本都是不可能.自己寫了個 測試了一下,貌似確實不可能.關鍵就在於,在程式執行的時候可以發現已經創造出了乙個列舉,但是沒有辦法使用,即沒有辦法例項化.下面是我的測試 有興趣的放vs上跑跑,呵呵 using system using system.th...