隨時記錄靈感 DP相關

2021-07-11 19:26:49 字數 4458 閱讀 2650

今天下午記錄的靈感因為沒有儲存所以消失了qaq

那就重寫一遍吧。

首先題目是這樣的:

有n個專案,每個專案都有m種東西可選,每個專案必須選乙個東西。

對於某個專案i,第j種東西:

有其效能wi

j 和花費ci

j 現在求 ma

x(mi

n(wi

j)∑c

ij)

設dp[i][j]表示到第i個選到的效能為j目前在考慮選不選第k個東西的最小花費。 dp

[i][

min(

j,w[

i][k

])=m

in(d

p[i−

1][j

]+c[

i][k

],dp

[i][

min(

j,w[

i][k

]))

嗯……然後最後掃一遍dp[n][j],每個j都除以dp[n][j]取最大的那個即可。

忽然感覺這好像乙個暴力啊……

像不像是列舉?

列舉每個專案,列舉每個東西,列舉每個東西能到達的結果。

我們可以考慮這種東西:

f[i][k][p]表示在第i個專案,目前最小的頻寬為k,花費為p可不可以到達。

那麼,顯然:

f[0][0][0][0] = 1;

然後轉移的話: f[

i][k

][p]

=f[i

−1][

s>=k]

[p−c

ij]|

f[i−

1][k

][p]

; 我們發現這種轉移簡直暴力到了一定地步,所以我們感覺……

現在我寫的dp就是乙個列舉

嗯……可是你怎麼保證你的dp不是列舉呢?

我的這個轉移,可以說,不是乙個dp

但是也是乙個dp啊,因為它有狀態,有轉移,沒有後效性。

問題在於:

原問題有乙個比較優美的性質,就是在於:

你不必儲存所有的花費可不可以到達,因為你只在乎那個最小的花費可不可以到達。

那麼我們把這個開個int陣列,然後省去一維,降一下空間就好了。

同樣的,我們的時間也減少了乙個n。

也就是說,我們根據問題的性質,成功降了一下維。

所以這就叫dp了?

我覺得這就是dp了吧。

我仔細回憶一下,可以發現幾個經典模型:

01揹包:

最蠢的暴力列舉:

f[i][j][k]表示第i個物品,容量為j,價值為k是可不可達的。

f[i][j][k] = f[i - 1][j - w][k - c] | f[i - 1][j][k]

最後暴力掃一遍每個狀態即可。

我們發現這樣的複雜度是(n ^ 3),但是比列舉每乙個物品選或者不選不知道要高貴到**去了。

思路:

暴力列舉每乙個物品?o(2n

) - > 影響最終答案,和最終答案有關的是什麼?選擇哪個物品,選還是不選,容量是怎樣的,價值是怎樣的。那麼,我們直接有上述轉移:f[i][j][k] = f[i - 1][j - w][k - c] | f[i - 1][j][k],即我們考慮最後掃一遍對於每個狀態可不可達,取一下最大值就行了。o(n3

) - >可是再仔細一想:我們只需要考慮每個容量記錄乙個最優的價值就好了,為什麼記錄比它還差的呢?沒錯,這樣做的最後轉移就是我們熟悉的: f[

i][j

]=ma

x(f[

i−1]

[j−w

[i]]

+c[i

],f[

i−1]

[j])

; 所以,此時並不關心你這個狀態可不可達,只關心在這個狀態可達的情況下,最優的結局是怎樣的

即:最優子結構

並且,由於問題的特殊性,我們顯然能知道,當前狀態的最優結局,我們在後面也會用到這一狀態的最優結局。並且,我們當前這一步的狀態對於後面的任何抉擇來講都是沒有影響的

即:無後效性

其實,當時我表示不是很理解:

在01揹包中,這個東西被選了,之後的選的就少了啊,這怎麼可能對後來的狀態沒有影響呢?

現在我好像明白了:

這種東西有沒有對後來狀態的影響,得根據當前狀態的定義來判斷。

比如對於01揹包,它選了這件物品,和不選這件物品,對於狀態定義的不同顯然結局不太一樣:

假設:f[i]表示強制選擇這個物品的最大價值。

顯然這個東西是沒辦法與後面產生什麼關係的。

因為f[i]和任意的乙個f[j]都沒有任何聯絡,它們不僅是互相影響的而且是沒有壓縮整個問題的。

而現在:

f[i][j] 表示對於第i個物品,還剩j容量的揹包能取得的最大價值。

顯然這一點跟前面取了什麼是無關的,這個狀態和什麼有關?

顯然這個狀態跟前面某個東西取或者沒有取是無關的,它只跟前面的揹包容量有關,甚至和前i - 1個物品都沒有任何關係。

再重複一遍當前狀態:第i個物品揹包容量為j的最大價值只與兩個狀態有關:

1.當前這個物品不選,前i - 1個物品,揹包容量為j的最大價值。

2.當前這個物品選了,前i - 1個物品,揹包容量為j - w[i]的最大價值。

只跟這兩個狀態有關,與

選了什麼到達了這些狀態

真的寫的有點累了呢……

我來冷靜一下:

我們來看一道經典的lis(最長不上公升子串行)問題

暴力列舉每個元素就不說了。

現在說說暴力列舉每個狀態:

設f[i][j][k]表示:前i個元素,長度為j可不可以通過大小為k的元素到達。

那麼問題分為兩部分:

選第i個,還是不選呢?

如果不選,那麼f[i][j][k]= f[i - 1][j][k]。

如果選呢?f[i][j][k] = f[i - 1][j - 1][s >= k];

所以最終結果是:

f[i][j][k] = f[i - 1][j][k] | (f[i - 1][j - 1][s >= k] && a[i] == k);

這樣問題就解決了!複雜度o(n3

∗w) 是不是非常蠢呢?

嗯……

我們考慮優化這個dp,發現我們並不用關心大小為k抑或是不是k,我們只關心前面的出現的那些元素。

設f[i][j][k]表示:前i個元素,長度為j可不可以通過第k大的元素到達。

f[i][j][k] = f[i - 1][j][k]\ \ \ | (f[i - 1][j - 1][s >= k] && a[i]排在第k大)

複雜度o(n4

)。 等等這好像還是有點蠢對吧……

因為你的第三維有n - 1個無用的狀態啊。

我們考慮這樣做:

f[i][j][0]表示對於前i個長度為j可不可以通過不選i到達。

f[i][j][1]表示對於前i個長度為j可不可以通過選i到達。 f[

i][j

][0]

=f[i

−1][

j][0

]|f[

i−1]

[j][

1]f[i][j][1] = f[i - 1][j][0] | f[k][j - 1][1] (k < i && a[k] > a[i])

其實這樣已經差不多了,我們發現複雜度是:o(n3

) 然而……

問題真的這樣結束了嗎?

我們考慮到一點,就是長度那一維應該是不用記的,因為我們同樣只關心這一點能造成的最優長度,不用關心比它差的結果。

於是我們: f[

i][0

]=ma

x(f[

i−1]

[0],

f[i−

1][1

])f[i][1] = max(f[i - 1][0],f[j][1](a[j] >= a[i] && j < i))

然後我們發現其實……

f[i][0]就是打醬油的,因為它什麼都派不上用場。

我們直接記錄強制選擇i所能達到的最大長度其實就解決了。

嗯實際上最終的複雜度是可以做到o(nl

og2n

)的,用樹狀陣列優化即可。

這個靈感應該還是蠻重要的。

至少dp其實算是暴力列舉每乙個狀態。

完結撒花。

隨時捕捉創業靈感

很多突破性的商業創意其實近在眼前,也許靈感就在你的房子裡 辦公室裡 車房或院子裡,只是其他人都渾然不覺。但你會發現自己全神貫注 反覆推敲,開始從這個創意的角度看世界。例如你開了一家像老紐約釀酒公司 oldnewyorkbrewingco.或溫哥華的格蘭維爾釀酒廠 grnvillebrewery 這種...

用 AutoHotKey 隨時記錄所想

別被標題咋呼了,其實很簡單,按下快捷鍵自動開啟指定文字文件,自動加上當前時間日期,適合像我這種無聊的人記錄生活。alt x 調出 x 獲取當前日期時間並儲存到剪貼簿 d rhinoc a yyyy a mm a dd a hour a min a sec clipboard d 開啟文字文件 run...

docker 使用相關問題(隨時更新)

最近又重拾docker遇到不少問題。1 is docker daemon running on this host?對於我來說有效的方法是 service docker start 啟動docker service 之後就可以了。2 docker compose的安裝 官網 docker compo...