動態規劃之狀態壓縮

2021-06-21 15:30:19 字數 2232 閱讀 3848

題目**是hdu 1074,題目大意是說:有幾門課的作業需要做,已知每門課作業的deadline和完成該作業需要花費的時間,求乙個作業的完成順序,使得最終的超時的天數最小。

比如,現在如下輸入:

computer 3 3

english 20 1

math 3 2

其中,第一列表示課程名,第二列表示deadline天數,第三列表示完成該作業需要的時間。

這題最開始看到的時候感覺沒有思路,後來參考這篇部落格才知道用狀態壓縮動態規劃,仔細分析了下這個演算法,發現就是列舉所有的狀態,然後找到代價最小的。由於對狀態壓縮不是特別了解,所以先寫下這題的解題報告,以後熟練了再做彙總和總結。下面先來詳細分析一下本題演算法的思想。

n門課程的完成順序,其實就是n門課程的全排列,最多有 n! 種可能。題目中給出 n <= 15, 則最多有 15!=1307674368000 中狀態,對這麼多狀態要求每一種狀態的代價,消耗的時間不可謂不高。總而言之,這種列舉法的時間複雜度是

考慮每門課的狀態,無非就是做與不做,用1和0兩個二進位制數就能表示了。這樣的話,n 個作業,用

以上面的輸入為例,下面是我畫的狀態轉移圖:

說明一下:右下角是各門課程的編碼,而中間狀態碼表示課程已經完成的狀態,比如 011 表示已經完成了課程 001 和 010 時的狀態。而 011 這個狀態有兩種進入途徑,一種是 001->010 ->011,一種是 010->001->011,兩種途徑代表了兩種作業執行順序。實際在選擇的時候要選擇代價(也就是圖中的delay)最小的進入途徑。圖中虛線箭頭表示最後輸出時通過 pre 引數進行的回溯,也即pre指向的是該狀態的前驅狀態。

乙個比較重要的現象是,對任意兩個相繼的狀態a, b (假設a是前驅,b是後繼), 則a^b(a,b異或)表示的是從狀態a到達狀態b時,選擇的作業的編碼是a^b。比如 011^111 = 100,則從011狀態抵達111狀態時,被執行的作業的編碼是100,也即是本例中的課程math。這點是回溯輸出時的乙個重要依據。

由於題目中說明了輸入的課程名已經按字典順序處理了,所以輸出時也是按字典順序選擇的。下面是ac的**:

//hdu 1074

//states compressing and dynamic programming

//0ms 760k 2775 b

#include #include #include using namespace std;

const int maxn = 1<<16;

struct coursecourse[15];

struct nodedp[maxn];

bool visited[maxn];

int max(int a, int b)

//stat是乙個二進位制狀態數,只有乙個 1,函式返回這個1在第幾位

int digit(int stat)

void print(int stat)

}

}

} cout<

補充說明,為什麼採用乙個二進位制數表示就能將狀態從階乘壓縮到指數數量級呢?我們取n=4時的情況來分析一下。當n=4時,如果直接窮舉所有狀態,則有4!=24種,如下:

1234     1243       1324       1342        1423          1432

2134      2143      2314       2341         2413         2431

3124      3142      3241       3214         3412         3421

4123      4132      4213       4231         4321         4312

注意到很多狀態都有相同的字首子串,比如狀態1234和1243有相同的字首子串 12, 都表示先做任務1和任務2,從理論上講,狀態1234和1243在前兩步(12)的執行結果是一樣的,可以重複使用。這就是本題使用動態規劃的基礎,對作為中間狀態的子問題進行儲存。如果仔細觀察上面的狀態轉移圖,不難看出,在狀態壓縮演算法中,每一層(相對於直接窮舉法裡面的每一步)的兩個狀態,其相同的部分都**於上一層(相當於上一步)的同乙個狀態。這是演算法能夠有效壓縮狀態的原因。同時,因為狀態之間的轉移是效率更高的位運算,使得演算法的效率得到大幅度提高。

狀態壓縮動態規劃

動態規劃的狀態有時候比較難,不容易表示出來,需要用一些編碼技術,把狀態壓縮的用簡單的方式表示出來。典型方式 當需要表示乙個集合有哪些元素時,往往利用2進製用乙個整數表示。一般有個資料 n 16 或者 n 32 這個很可能就是狀態dp的標誌,因為我們要用乙個int的二進位制來表示這些狀態。要注意好這些...

動態規劃 狀態壓縮

這個題目的題意很容易理解,在乙個n m的格仔裡,我們現在有兩種型別的磚塊,1 2和 2 1,問一共有多少種方案,可以將整個n m的空間都填滿。最簡單的例子就是下面的了 程式設計之美中題目 某年夏天,位於希格瑪大廈四層的微軟亞洲研究院對辦公樓的天井進行了一次大規模的裝修.原來的地板鋪有 n m 塊正方...

狀態壓縮動態規劃

我們可以使用乙個01串a來表示乙個集合。對於數x x 0 用ax 0表示它不在該集合中,用ax 1表示它在該集合中。將01串a看作是乙個二進位制數,我們把它轉換為十進位制,就可以使用乙個十進位制整數來表示乙個實際使用二進位制方式表示的集合。這樣,我們可以使用位運算方便地處理集合的操作。交集兩個集合a...