今天下午記錄的靈感因為沒有儲存所以消失了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...