基礎演算法之動態規劃 狀態壓縮DP

2021-10-10 05:13:17 字數 2885 閱讀 9785

狀態壓縮是指用二進位制表示集合的方式對狀態進行壓縮,將其表示為乙個整數。

例如:用二進位制表示乙個集合的子集。

集合 s

=s = \

s=,那麼二進位制數(

01001)2

(01001)_2

(01001

)2​,表示的就是s

ss的乙個子集s′=

s' = \

s′=,該子集可以用乙個十進位制數9

99來表示。

狀態壓縮dp其實是動態規劃類問題中一種特殊的狀態表示方式。若要表示的集合元素數量比較少(不超過20)時,想要儲存每個元素取或者不取時,可以借助位運算將狀態壓縮。需要借助狀態壓縮實現狀態表示的dp問題就稱為狀態壓縮dp。

例如取若干元素,如果選擇的話對應位置記為1,其餘位置記為0。例如一共有5個元素a,b

,c,d

,e

a,b,c,d,e

a,b,c,

d,e,分別用1,2

,4,8

,16

1,2,4,8,16

1,2,4,

8,16

表示這5個元素,則集合

\可以用(

00101)2

=3

(00101)_2 = 3

(00101

)2​=

3來表示,而集合

\可以用(

11010)2

=26

(11010)_2=26

(11010

)2​=

26表示。對於元素個數為n

nn的情況,其空間複雜度為(2n

)(2^n)

(2n)。n

nn個人在做傳遞物品的遊戲,編號為1

11-nnn。

即物品只能經過同乙個人一次,而且每次傳遞過程都有乙個代價;不同的人傳給不同的人的代價值之間沒有聯絡;

求當物品經過所有n

nn個人後,整個過程的總代價是多少。

輸入描述

第一行為n

nn,表示共有n

nn個人(2≤n

≤16

2≤n≤16

2≤n≤16

)。以下為n×n

n×nn×

n的矩陣,第i+1

i+1i+

1行、第j

jj列表示物品從編號為i

ii的人傳遞到編號為j

jj的人所花費的代價,特別的有第i+1

i+1i+

1行、第i

ii列為−1-1

−1(因為物品不能自己傳給自己),其他資料均為正整數(<

=1000

<=1000

<=1

000)。

輸出描述

乙個數,為最小的代價總和。

輸入樣例

3

-1 2 4

3 -1 5

4 4 -1

輸出樣例

在傳遞過程中,當前狀態可以表示為哪些人已經傳遞過物品、並且物品目前傳遞到哪個人手上。而已經傳遞過物品的人可以理解為從集合中已選取了哪些元素,因此可以使用狀態壓縮的方式,用二進位制數01來表示未傳遞和已傳遞的兩種狀態。

f[s][j]表示當前傳遞狀態的集合為s、並且傳遞到編號為j的人手中時的最小的代價總和。

物品需要從上乙個人(不妨設編號為i)傳遞過來,因此需要列舉所有可以傳遞到j的人,取其中最小的代價總和。可以傳遞到j,意味著編號為i的人已經包含在集合s中。

狀態轉移方程:f[s

][j]

=min⁡]

[i]}

+w[i

][j]

f[s][j] = \min\][i]\} + w[i][j]

f[s][j

]=min][i

]}+w

[i][

j]其中:f[s

−][i

]f[s - \][i]

f[s−][

i]表示集合s中不包含j,即編號j的人尚未被傳遞過物品。

題目中求最小值,因此首先將f陣列初始化為無窮大。其次,從自己出發且傳遞給自己時,最小代價為0,即f[1 << i][i] = 0

狀態數2n×

n2^n \times n

2n×n

,轉移過程要迴圈n

nn次,所以時間複雜度為o(2

n×n2

)o(2^n\times n^2)

o(2n×n

2)

#include

#include

using

namespace std;

const

int n =

16, inf =

0x3f3f3f3f

;int w[n]

[n], f[

1<< n]

[n];

intmain()

}}}}

int res = inf;

//打擂台求出,傳遞過所有人後,且最後在i手上時的最小值

for(

int i =

0; i < n; i ++

) cout << res << endl;

return0;

}

動態規劃 狀態壓縮dp

if cnt 1 return false 用來判斷像01這種最後是0的情況 return true int main return 0 預處理所有狀態是否為合法狀態 include include include using namespace std typedef long long ll c...

動態規劃 dp狀態的壓縮

1312.讓字串成為回文串的最少插入次數 給你乙個字串 s 每一次操作你都可以在字串的任意位置插入任意字元。請你返回讓 s 成為回文串的 最少操作次數 回文串 是正讀和反讀都相同的字串。示例 1 輸入 s zzazz 輸出 0 解釋 字串 zzazz 已經是回文串了,所以不需要做任何插入操作。示例 ...

動態規劃之狀態壓縮

題目 是hdu 1074,題目大意是說 有幾門課的作業需要做,已知每門課作業的deadline和完成該作業需要花費的時間,求乙個作業的完成順序,使得最終的超時的天數最小。比如,現在如下輸入 computer 3 3 english 20 1 math 3 2 其中,第一列表示課程名,第二列表示dea...