通過例題進一步學習DP

1.以上篇文章數塔爲例 https://blog.csdn.net/weixin_43627118/article/details/88701586
在這裏插入圖片描述
上一章用的是遞歸的做法,這次我們採用遞推的做法。

遞歸:從已知問題的結果出發,用迭代表達式逐步推算出問題的開始的條件,即順推法的逆過程,稱爲遞歸。
遞推:遞推算法是一種用若干步可重複運算來描述複雜問題的方法。遞推是序列計算中的一種常用算法。通常是通過計算機前面的一些項來得出序列中的指定象的值。
遞歸與遞推區別:相對於遞歸算法,遞推算法免除了數據進出棧的過程,也就是說,不需要函數不斷的向邊界值靠攏,而直接從邊界出發,直到求出函數值。
斐波那契數列:已知f(1) = 1 , f(2) = 1 , 且滿足關係式f(n) = f(n-1) + f(n-2),則f(50)等於多少?
分析:根據初始條件f(1) = 1 , f(2) = 1 和關係式f(n) = f(n-1) + f(n-2),可知,f(3) = f(2) + f(1) , f(3) = f(2) + f(1) …….
編寫代碼(遞歸)

第四層的取值等於左下或者右下與自己的加和,第四層就有max{2+19,2+7} max{18+7,18+10} max{9+10,9+4} max{5+4,5+16}
結果第四層就變成了 21,28,19,21。這樣五層變成了四層。以此類推n層變爲n-1層到1層。更易求出最大值。
代碼實現過程如下

#include<bits/stdc++.h>
using namespace std;
int main
{
	int ob[10][10];
	int temp;
	cin>>N;//數塔層數
	for(int i=0;i<N;i++)
	{
		for(t=0;t<=i;t++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=N-1;i>=1;i--)
	{
		for(int t=0;t<=i;t++)
		{
			temp=max{a[i+1][t],a[i+1][t+1];
			a[i][t]=a[i][t]+temp;
		}
	}
1、線性模型
   線性模型的是動態規劃中最常用的模型,上文講到的最長單調子序列就是經典的線性模型,這裏的線性指的是狀態的排布是性的。
   2、區間模型
  區間模型的狀態表示一般爲d[i][j],表示區間[i, j]上的最優解,然後通過狀態轉移計算出[i+1, j]或者[i, j+1]上的最優解,逐步擴大區間的範圍,最終求得[1, len]的最優解。

3、揹包模型
揹包問題是動態規劃中一個最典型的問題之一。由於網上有非常詳盡的揹包講解,這裏只將常用部分抽出來,具體推導過程詳見 《揹包九講》。
a.0/1揹包
有N種物品(每種物品1件)和一個容量爲V的揹包。放入第 i 種物品耗費的空間是Ci,得到 的價值是Wi。求解將哪些物品裝入揹包可使價值總和最大。
f[i][v]表示前i種物品恰好放入一個容量爲v的揹包可以獲得的最大價值。
決策爲第i個物品在前i-1個物品放置完畢後,是選擇放還是不放,狀態轉移方程爲:
f[i][v] = max{ f[i-1][v], f[i-1][v - Ci] +Wi }
時間複雜度O(VN),空間複雜度O(VN) (空間複雜度可利用滾動數組進行優化達到O(V),下文會介紹滾動數組優化)。

 b.完全揹包
            有N種物品(每種物品無限件)和一個容量爲V的揹包。放入第 i 種物品耗費的空間是Ci,得到 的價值是Wi。求解將哪些物品裝入揹包可使價值總和最大。
            f[i][v]表示前i種物品恰好放入一個容量爲v的揹包可以獲得的最大價值。
           f[i][v] = max{ f[i-1][v - kCi] + kWi  | 0 <= k <= v/Ci  }        (當k的取值爲0,1時,這就是01揹包的狀態轉移方程)
           時間複雜度O( VNsum{V/Ci} ),空間複雜度在用滾動數組優化後可以達到 O( V )。
           進行優化後(此處省略500字),狀態轉移方程變成:
           f[i][v] = max{ f[i-1][v],  f[i][v - Ci] +Wi }   
           時間複雜度降爲 O(VN)。
  c.多重揹包
           有N種物品(每種物品Mi件)和一個容量爲V的揹包。放入第i種物品耗費的空間是Ci,得到 的價值是Wi。求解將哪些物品裝入揹包可使價值總和最大。
           f[i][v]表示前i種物品恰好放入一個容量爲v的揹包可以獲得的最大價值。
           f[i][v] = max{ f[i-1][v - kCi] + kWi  | 0 <= k <= Mi }
           時間複雜度O( Vsum(Mi) ), 空間複雜度仍然可以用滾動數組優化後可以達到 O( V )。
           優化:採用二進制拆分物品,將Mi個物品拆分成容量爲1、2、4、8、... 2^k、Mi-( 2^(k+1) - 1 ) 個對應價值爲Wi、2Wi、4Wi、8Wi、...、2^kWi、( Mi-( 2^(k+1) - 1 )

)Wi的物品,然後採用01揹包求解。 這樣做的時間複雜度降爲O(Vsum(logMi) )。找不到出處了

給定一個字符串s,你可以從中刪除一些字符,使得剩下的串是一個迴文串。如何刪除才能使得迴文串最長呢?
輸出需要刪除的字符個數。

本題可轉化爲動態規劃算法求解最長公共子序列問題,然後用總字符串長度減去最長子序列長度,便得出問題的答案。

先將給定的初始字符串S1反過來排列,設爲S2,求S1和S2的最長公共子序列便可。C++代碼如下:

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int temp[100][100];

void caculate(string s1){
	string s2(s1);
	reverse(s2.begin(), s2.end());
	int len = s1.length();
	memset(temp, 0, sizeof(temp));
	for (int i = 0; i<len; ++i)
	{
		for (int j = 0; j<len; ++j)
		{
			if (s1[i] == s2[j])
				temp[i + 1][j + 1] = temp[i][j] + 1;
			else 
				temp[i + 1][j + 1] = max(temp[i][j + 1], temp[i + 1][j]);
		}
	}
	cout << len - temp[len][len] << endl;
}

int main()
{
	string s;
	getline(cin, s);
	caculate(s);
	system("pause");
	return 0;
}

動態規劃分類有很多劃分方法,網上有很多是按照狀態來分,分爲一維、二維、區間、樹形等等。我覺得還是按功能即解決的問題的類型以及難易程度來分比較好,下面按照我自己的理解和歸納,把動態規劃的分類如下:

一、簡單基礎dp

這類dp主要是一些狀態比較容易表示,轉移方程比較好想,問題比較基本常見的。主要包括遞推、揹包、LIS(最長遞增序列),LCS(最長公共子序列),下面針對這幾種類型,推薦一下比較好的學習資料和題目。

1、遞推:

遞推一般形式比較單一,從前往後,分類枚舉就行。

簡單:

hdu 2084 數塔 簡單從上往下遞推

hdu 2018 母牛的故事 簡單遞推計數

hdu 2044 一隻小蜜蜂… 簡單遞推計數(Fibonacci)

hdu 2041 超級樓梯 Fibonacci

hdu 2050 折線分割平面 找遞推公式

推薦:

CF 429B B.Working out 四個角遞推

zoj 3747 Attack on Titans 帶限制條件的計數遞推dp

uva 10328 Coin Toss 同上題

hdu 4747 Mex

hdu 4489 The King’s Ups and Downs

hdu 4054 Number String

2、揹包

經典的揹包九講:http://love-oriented.com/pack/

推薦博客:http://blog.csdn.net/woshi250hua/article/details/7636866

主要有0-1揹包、完全揹包、分組揹包、多重揹包。

簡單:

hdu 2955 Robberies 01揹包

hdu 1864 最大報銷額 01揹包

hdu 2602 Bone Collector 01揹包

hdu 2844 Coins 多重揹包

hdu 2159 FATE 完全揹包

推薦:

woj 1537 A Stone-I 轉化成揹包

woj 1538 B Stone-II 轉化成揹包

poj 1170 Shopping Offers 狀壓+揹包

zoj 3769 Diablo III 帶限制條件的揹包

zoj 3638 Fruit Ninja 揹包的轉化成組合數學

hdu 3092 Least common multiple 轉化成完全揹包問題

poj 1015 Jury Compromise 擴大區間+輸出路徑

poj 1112 Team Them UP 圖論+揹包

3、LIS

最長遞增子序列,樸素的是o(n^2)算法,二分下可以寫成o(nlgn):維護一個當前最優的遞增序列——找到恰好大於它更新

簡單:

hdu 1003 Max Sum

hdu 1087 Super Jumping!

推薦:

uva 10635 Prince and Princess LCS轉化成LIS

hdu 4352 XHXJ’s LIS 數位dp+LIS思想

srm div2 1000 狀態壓縮+LIS

poj 1239 Increasing Sequence 兩次dp

4、LCS

最長公共子序列,通常o(n^2)的算法

hdu 1503 Advanced Fruits

hdu 1159 Common Subsequence

uva 111 History Grading 要先排個序

poj 1080 Human Gene Functions

二、區間dp

推薦博客:http://blog.csdn.net/woshi250hua/article/details/7969225

區間dp,一般是枚舉區間,把區間分成左右兩部分,然後求出左右區間再合併。

poj 1141 Brackets Sequence 括號匹配並輸出方案

hdu 4745 Two Rabbits 轉化成求迴文串

zoj 3541 The Last Puzzle 貪心+區間dp

poj 2955 Brackets

hdu 4283 You Are the One 常見寫法

hdu 2476 String Printer

zoj 3537 Cake

CF 149D Coloring Brackets

zoj 3469 Food Delivery

三、樹形dp

比較好的博客:http://blog.csdn.net/woshi250hua/article/details/7644959

一篇論文:http://doc.baidu.com/view/f3b19d0b79563c1ec5da710e.html

樹形dp是建立在樹這種數據結構上的dp,一般狀態比較好想,通過dfs維護從根到葉子或從葉子到根的狀態轉移。

hdu 4123 Bob’s Race 二分+樹形dp+單調隊列

hdu 4514 求樹的直徑

poj 1655 Balancing Act

hdu 4714 Tree2Cycle 思維

hdu 4616 Game

hdu 4126 Genghis Kehan the Conqueror MST+樹形dp 比較經典

hdu 4756 Install Air Conditioning MST+樹形dp 同上

hdu 3660 Alice and Bob’s Trip 有點像對抗搜索

CF 337D Book of Evil 樹直徑的思想 思維

hdu 2196 Computer 搜兩遍

四、數位dp

推薦一篇論文:http://wenku.baidu.com/view/d2414ffe04a1b0717fd5dda8.html

數位dp,主要用來解決統計滿足某類特殊關係或有某些特點的區間內的數的個數,它是按位來進行計數統計的,可以保存子狀態,速度較快。數位dp做多了後,套路基本上都差不多,關鍵把要保存的狀態給抽象出來,保存下來。

hdu 2089 不要62 簡單數位dp

hdu 3709 Balanced Number 比較簡單

CF 401D Roman and Numbers 狀壓+數位dp

hdu 4398 X mod f(x) 把模數加進狀態裏面

hdu 4734 F(x) 簡單數位dp

hdu 3693 Math teacher’s homework 思維變換的數位dp

hdu 4352 XHXJ’s LIS 數位dp+LIS思想

CF 55D Beautiful Numbers 比較巧妙的數位dp

hdu 3565 Bi-peak Numbers 比較難想

CF 258B Little Elephant and Elections 數位dp+組合數學+逆元

五、概率(期望) dp

推薦博客:http://www.cnblogs.com/kuangbin/archive/2012/10/02/2710606.html

推薦博客:http://blog.csdn.net/woshi250hua/article/details/7912049

推薦論文:

《走進概率的世界》

《淺析競賽中一類數學期望問題的解決方法》

《有關概率和期望問題的研究》

一般來說概率正着推,期望逆着推。有環的一般要用到高斯消元解方程。期望可以分解成多個子期望的加權和,權爲子期望發生的概率,即
E(aA+bB+…) = aE(A) + bE(B) +…

ural 1776 Anniversiry Firework 比較基礎

hdu 4418 Time travel 比較經典BFS+概率dp+高斯消元

hdu 4586 Play the Dice 推公式比較水

hdu 4487 Maximum Random Walk

jobdu 1546 迷宮問題 高斯消元+概率dp+BFS預處理

hdu 3853 LOOPS 簡單概率dp

hdu 4405 Aeroplane chess 簡單概率dp,比較直接

hdu 4089 Activation 比較經典

poj 2096 Collecting Bugs 題目比較難讀懂

zoj 3640 Help me Escape 從後往前,比較簡單

hdu 4034 Maze 經典好題,藉助樹的概率dp

hdu 4336 Card Collector 狀態壓縮+概率dp

hdu 4326 Game 這個題狀態有點難抽象

六、狀態壓縮dp

這類問題有TSP、插頭dp等。

推薦論文:http://wenku.baidu.com/view/ce445e4f767f5acfa1c7cd51.html

推薦博客:http://blog.csdn.net/sf____/article/details/15026397

推薦博客:http://www.notonlysuccess.com/index.php/plug_dp/

hdu 1693 Eat the Trees 插頭dp

hdu 4568 Hunter 最短路+TSP

hdu 4539 插頭dp

hdu 4529 狀壓dp

poj 1185 炮兵陣地

poj 2411 Mandriann’s Dream 輪廓線dp

hdu 3811 Permutation

poj 1038

poj 2441

hdu 2167

hdu 4026

hdu 4281

七、數據結構優化的dp

有時儘管狀態找好了,轉移方程的想好了,但時間複雜度比較大,需要用數據結構進行優化。常見的優化有二進制優化、單調隊列優化、斜率優化、四邊形不等式優化等。

1、二進制優化

主要是優化揹包問題,揹包九講裏面有介紹,比較簡單,這裏只附上幾道題目。

hdu 1059 Diving

hdu 1171 Big Event in Hdu

poj 1048 Follow My Magic

2、單調隊列優化

推薦論文:http://wenku.baidu.com/view/4d23b4d128ea81c758f578ae.html

推薦博客:http://www.cnblogs.com/neverforget/archive/2011/10/13/ll.html

hdu 3401 Trade

poj 3245 Sequece Partitioning 二分+單調隊列優化

3、斜率優化

推薦論文:用單調性優化動態規劃

推薦博客:http://www.cnblogs.com/ronaflx/archive/2011/02/05/1949278.html

hdu 3507 Print Article

poj 1260 Pearls

hdu 2829 Lawrence

hdu 2993 Max Average Problem

4、四邊形不等式優化

推薦博客:http://www.cnblogs.com/ronaflx/archive/2011/03/30/1999764.html

推薦博客:http://www.cnblogs.com/zxndgv/archive/2011/08/02/2125242.html

hdu 2952 Counting Sheep

poj 1160 Post Office

hdu 3480 Division

hdu 3516 Tree Construction

hdu 2829 Lawrence
摘自博客地址 https://blog.csdn.net/qq_41785863/article/details/81489269
矩陣連乘問題,紙牌問題,石頭合併問題(都是一類問題,一起分析)

給定n個矩陣{A1,A2……An},其中A【i】與A【i+1】是可乘的,如何確定計算的次序,使得乘法的總次數最少

首先我們要明白,計算的次序不同,那麼乘法的總次數也不同

類似的問題:給你n張牌,每張排都有一個數字,相鄰的兩張牌的權值可以相乘,相乘的兩張牌可以合併爲

一張牌,新牌的權值是原來的兩張牌的乘積

這個問題還有石頭合併問題都是同一類的問題,屬於區間dp問題

石頭合併問題:給你一堆石頭,排成一行,相鄰的兩個石頭可以合併,合併成的石頭的權值爲原來兩個石頭

的權值之和

先來分析矩陣連乘問題:

給你一個一維數組

30,35,15,5,10,20,25

只要相鄰的矩陣纔可以相乘

思考一下,dp的思想是如何體現的

第一步我們是要把問題分解成很多互相有聯繫的子問題(重複子問題是用dp的基礎)

簡單的思考一下,每次矩陣相乘,最簡單的就是兩個可以相乘的矩陣相乘(A1,A2,A3),那最大的乘法次數就是A1A2A3

但是如果是多個呢,我們是不是可以簡化成下面這樣

A【i】,A【i+1】………………….A【k】………………A【j-1】,A【j】

講他們分成兩個抽象矩陣

第一個:A【i】….A【k】

第二個:A【k+1】……A【j】

把大問題抽象成兩個抽象矩陣相乘,那麼更加最簡單的那種抽象一下就知道求所有矩陣乘法的最大次數,就

是求第一個抽象矩陣自己內部要乘的次數和第二個抽象矩陣內部自己要求的乘法次數然後加上這這兩個抽象

矩陣合併爲一個大的抽象矩陣要乘的次數

那麼大問題是這樣的,大問題裏面是不是有很多這樣的小問題,而且這些小問題還是重複的,比如A【k】

的選擇不同,那麼乘的次序結果也不一樣,A【k】的選擇可以導致很多問題都有重複的部分,如果多次計

算的話,無疑是很不明智的,這樣的話跟分治就是沒有什麼區別了,這樣的問題就叫做重複子問題

A【k】的選擇不同的話,會導致子問題有很多重複的部分,前面我們說了的,同時A【k】的選擇不同的話

會導致兩個抽象矩陣相乘的結果也不一樣,所以我們就要在所有的A【k】選擇中找一個最小的

所以我們現在在這個問題裏面找到了dp思想的具體體現:大量的重複子問題

具體做法:

dp【i】【j】:代表矩陣i,矩陣i+1………….矩陣j的最少乘法次數

總結上述:

dp【i】【j】=min(dp【i】【k】+dp【k+1】【j】

i<=k<=j-1 https://blog.csdn.net/qq_39382769/article/details/80788294

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章