題面
poj2279題面
思路
從頭開始系統的學dp,做題目一定要理清dp的五大因素
狀態表示
用dp[a1,
a2,a
3,a4
,a
5a_1,a_2,a_3,a_4,a_5
a1,a2
,a3
,a4
,a5
]表示第i行上已經插入了a
ia_i
ai個人的排隊方法數
階段劃分
已經在各排分配了制定人數的方法數(對應乙個五元組)
轉移方程
寫不下了^ _ ^下面單列
邊界dp[0,0,0,0,0]=1,其餘均為0
目標dp[k1,
k2,k
3,k4
,k
5k_1,k_2,k_3,k_4,k_5
k1,k2
,k3
,k4
,k5
]轉移方程及其理解:
d p[
a1,a
2,a3
,a4,
a5]=
dp[a_1,a_2,a_3,a_4,a_5]+dp[a_1-1,a_2,a_3,a_4,a_5] (a_1\geq 1 \space and \space a_1\leq k_1)\\ dp[a_1,a_2,a_3,a_4,a_5]+dp[a_1,a_2-1,a_3,a_4,a_5] (1 \leq a_2\leq a_1 \space and \space a_2\leq k_2)\\ \vdots \\ dp[a_1,a_2,a_3,a_4,a_5]+dp[a_1,a_2,a_3,a_4,a_5-1] (1 \leq a_5\leq a_4 \space and \space a_5\leq k_5) \end
dp[a1
,a2
,a3
,a4
,a5
]=⎩⎪
⎪⎪⎪⎨
⎪⎪⎪⎪
⎧dp
[a1
,a2
,a3
,a4
,a5
]+dp
[a1
−1,a
2,a
3,a
4,a
5](
a1≥
1and
a1≤
k1)
dp[a
1,a
2,a
3,a
4,a
5]+
dp[a
1,a
2−1
,a3
,a4
,a5
](1≤
a2≤
a1a
nda2
≤k2
)⋮d
p[a1
,a2
,a3
,a4
,a5
]+d
p[a1
,a2
,a3
,a4
,a5
−1]
(1≤a
5≤a
4an
da5
≤k5
)其實狀態的尋找是不好做的,對於最終目標,如何找出表示目標的維度,如何分解問題,使其在求解每個子問題的"階段"都具有"子問題重疊性",「無後效性"和"最優子結構性質」。
性質解釋
子問題重疊性
問題可劃分成多個子問題,並且子問題具有相似性,可以歸納
無後效性
已經求解的子問題不受後續階段的影響
最優子結構性質
下一階段的最優解能夠由前面各階段的子問題的最優解匯出
這三個性質是判斷尋找的狀態是否具有動態規劃條件的性質。
能想到的是,對於乙個人的狀態肯定可以計算,用乙個人算兩個人的狀態也可以算,而後面的狀態加乙個人好像也可以算,仔細想一下,如果自己打個表的話,可以從1開始人數乙個乙個向上推(其實就是動態規劃的模擬),想到這種模擬,基本上三個性質都具備了(請讀者自行思考),如果想到人數為維度的話,為了能夠表示每一排的情況,容易想到用五元組表示狀態的方法。
對於初態,如果五個空都沒有乙個人的話,肯定預設只有一種排法,所以dp[0,0,0,0,0]=1,對於剛剛所謂的乙個人乙個人地向上推,其實就是對於當前狀態對於五元組每乙個元討論少乙個人的情況,假設我們插人是從低到高插入的,那個人排在哪一排反正是從低到高排肯定在是固定的在排首的,其實就是其他人的站位影響了照相順序,也就是加上其他人站位的方法數即可(就是+dp
[a1,
a2−1
,a3,
a4,a
5]
+dp[a_1,a_2-1,a_3,a_4,a_5]
+dp[a1
,a2
−1,
a3,
a4,
a5]
這類的原因 ),但是這保證了每一排是從低到高,但要保證每一列從低到高,那就要當第i-1排比i排少人的時候,就不能排在第i排,因為下面總有乙個更高的要插在i-1排,就不是從低到高了,同時還要滿足插人不多於給出的限制,那就是(1≤
ai≤a
i−1a
ndai
≤ki)
(1 \leq a_i\leq a_i-1 \space and \space a_i\leq k_i)
(1≤ai
≤ai
−1an
dai
≤ki
)了唄注意事項
1)dp一般0陣列的0軸是初態,所以一般迴圈要<=限制,答案訪問上界而不是上界-1
2)要注意陣列(無向圖)的遍歷的範圍,不要少了也不要越界
3)函式內部按大小直接宣告dp陣列,否則會mle(c++14以上的編譯器陣列可以直接用變數宣告)
**
//這個是按照上面的轉移方程寫的,是在此狀態訪問上一次狀態的情況
#include #include using namespace std;
typedef long long ll;
const int maxn = 31;
int nk[6];
int main()
ll dp[nk[0]+1][nk[1]+1][nk[2]+1][nk[3]+1][nk[4]+1];
memset(dp,0,sizeof(dp));
dp[0][0][0][0][0] = 1;
for(int i = 0;i <= nk[0];i++)}}
}}
cout << dp[nk[0]][nk[1]][nk[2]][nk[3]][nk[4]]=1了,
//需要在i ==k[1]的時候阻止其進一步向下求,也就是要有(i < n[1])的判斷
#include #include #include typedef long long ll;
using namespace std;
int n[6], k;
void work()
cout << f[n[1]][n[2]][n[3]][n[4]][n[5]] << endl;
}int main()
POJ 1187 隕石的秘密 (線性DP)
題意 公元11380年,一顆巨大的隕石墜落在南極。於是,災難降臨了,地球上出現了一系列反常的現象。當人們焦急萬分的時候,一支中國科學家組成的南極考察隊趕到了出事地點。經過一番偵察,科學家們發現隕石上刻有若干行密文,每一行都包含5個整數 1 1 1 1 6 0 0 6 3 57 8 0 11 3 28...
POJ 2948 經典二維dp
一開始不知道怎麼解決後效性,以為自己記錄狀態的方式錯了,實際上是轉移方程想錯了 學習了 如果怎麼dp都發覺有後效性,一定是dp的姿勢不對 dp i j 如果採用向左的決策,要從dp i 1 j 轉移過來,如果採用向上的決策,要從dp i j 1 轉移過來,這樣前面的方程裡怎麼決策才不會對後來那個方程...
相似基因,二維的線性dp
時間限制 1.0s 空間限制 2.5mb 大家都知道,基因可以看作乙個鹼基對序列。它包含了4種核苷酸,簡記作a,c,g,t。生物學家正致力於尋找人類基因的功能,以利用於診斷疾病和發明藥物。在乙個人類基因工作組的任務中,生物學家研究的是 兩個基因的相似程度。因為這個研究對疾病的 有著非同尋常的作用。兩...