這道題是我第一次接觸狀態壓縮dp,記錄下來留個紀念吧。
題目大意:輸入t表示案例數,每個案例首先輸入n表示學科數。接下來有n行,每行三個資料分別是學科名字、學科作業的截止天數、做這門學科的作業需要耗費的天數。當超過某一門學科的截止時間完成作業的時候,超過幾天就扣多少分,學科名字按照字典序遞增的順序輸入。要求輸出乙個做作業的順序,使得扣分最少。如果有多個做作業的順序扣分都最少,輸出按照字典序排列的做作業順序。
首先的乙個思路就是,這道題目裡面,狀態的定義就是哪門學科已經做完,哪門學科還沒有做完。但是要表示這些狀態非常麻煩,於是可以使用狀態壓縮,比如一共五門學科,學科0到學科4,採用五個二進位制位表示,0表示作業沒有做完,1表示作業做完了。如00011表示學科0和學科1作業做完了。這樣的話我們的目標就是求從00000狀態到11111最少扣分。
11111狀態的的到達有五種可能:1、11110狀態做完學科0後到達。2、11101狀態做完學科1後到達。。。。。。等等一共五個狀態。我們計算00000->11110->11111 00000->11101->11111等等五種狀態變遷,計算最小扣分數。
這裡還有乙個問題,輸出的序列要按照字典序公升序的排序。我是按照題目給的示例輸入考慮的。針對第二個示例輸入:c 3 3, e 6 3,m 6 3。按照cem和cme的順序做作業的話都可以使得扣分最少。我們期望的是做完m以後達到狀態111,這樣的話學科順序是字典序公升序排列的。我們需要遍歷111狀態所有的前乙個狀態110,101,011以確定怎麼狀態轉移扣分最少。我們發現按照學科倒序遍歷的話,首先遍歷了學科m,從011狀態做完學科m之後達到111狀態扣分最少,並且符合要求的輸出,所以我們採用倒序遍歷學科的順序。(之前看網上的**對於為什麼倒序遍歷解釋的都非常模糊,這是我自己的理解,要是有更好的理解的話歡迎指出)
定義資料結構如下:
struct state;
state表示學科狀態,最多15個學科,那麼學科狀態最多有(1<<15)即2.^15種狀態(每個學科都有做完或沒有做完兩種)。任意一種狀態k,state[k].prestate表示從0狀態(所有學科都沒做)到prestate狀態,再做完一門學科到k狀態,扣分最少,sub為做的那個學科,reduce為從學科狀態0到學科狀態k的最少扣分,days表示從學科狀態0到學科狀態k花費的總天數。
一共n門學科,我們的目標就是求state[(1<#include#include#includeusing namespace std;
struct subject;
//state[k]:
struct state;
int t,n;
state state[1<<15+5];
subject subject[18];
stacks;
void dp()
}
hdu1074狀態壓縮
很明顯的狀態壓縮題目。當然了如果他的意識只有是求最小值沒有要求輸出那個輸出的順序,那麼直接用揹包,甚至是貪心都是可以做出來的,但是要求順序這個揹包的話沒有辦法吧資料記錄下來。所以用二進位制壓縮。所謂的二進位制壓縮就是用二進位制來表示事情的完成程度和狀況,比如1,就是0000001表示第乙個作業做了,...
1074 HDU 狀態壓縮
首先貼兩個狀態壓縮的題解,這是第乙個狀態壓縮dp,想了一下午,不知道是不是有點慢 然後在貼下我自己的 include include include include include include include include define ll int64 define max 1000009 ...
hdu 1074 狀態壓縮
我們可以斷定狀態的終止態一定是n個數全部選完的情況,那麼它的前乙個狀態是什麼呢,一定是剔除任一門課程後的n種狀態。例如dp 全選了 min那麼接下來的dp狀態依然如此。好了,接下來,我們該如何去思考了,這個題目共有2 15種可能情況,對此我們通過位運算的方法降低它的維度。二進位制的每一位代表一門課,...