基礎線性DP總結

2021-09-18 06:00:02 字數 3869 閱讀 4155

動態規劃是一種求解最優解的思想 。通常情況下要分清楚動規和貪心,什麼時候用貪心,什麼時候用動規。

動規方程:dp[i][j]=a[i][j]+max。每次從i,j走有兩種選擇下dp[i+1][j]和 右下dp[i+1][j+1].全域性最優解包含區域性最優解。動態規劃的核心是狀態轉移方程。

這是數字三角形的基礎題。

#include#include#include#includeusing namespace std;

const int maxn=101;

int dp[maxn][maxn];

int main()

}for(int i=n-1;i>=1;i--)//從後往前搜尋

}cout《需要注意邊界,我從0開始到n,一直wrong,後來把邊界條件改了,就過了,注意是從下往上搜尋。動態規劃不同於遞迴,遞迴會有很多相同子問題,會造成效率很低,動規是從底往上搜尋。輸出的是最上層dp[1][1]就是所求解。

此題可以用滾動陣列進行優化,能降低空間複雜度,滾動陣列就是在資料量很大的時候壓縮儲存。達到節省空間的思想。

#include#include#include#includeusing namespace std;

const int maxn=101;

int dp[maxn][maxn];

int *maxsum;

int main()

}maxsum=dp[n];//maxsum指向第n行

for(int i=n-1;i>=1;i--)//從後往前搜尋

}cout這道題就是數字三角形的變形,最後要從(0,5)輸出。倒推。

#include#include#include#includeusing namespace std;

const int maxn=100001;

int dp[maxn][12];

//dp[t][x]代表在第t秒的餅的數量x

int max_cnt(int a,int b,int c)

int main()

}for(int i=maxn-1;i>=0;i--)

//cout《這道題真的很棒。想了半小時都不知道該如何入手,我是真的笨,主要還是練的比較少。

思路:子問題:看這道題能不能分成子問題,分為的子問題的子問題是否一樣,有無後效性。

子問題:跳到板子上,有兩種選擇,向左走或者向右走,向左走和向右走,走到左端火星和走到右端所需的時間是很容算的,如果我們能知道以左端為起點到達地面的最短時間和以右端為起點到達地面的最短時間,那麼向左走還是向右走,就比較容易選擇。因此該問題可以被分為兩個子問題,以左端為起點到達地面的最短時間和以右端為起點到達地面的最短時間,兩個子問題的子問題也是如此,無後效性,將板子從上到下從1開始進行無重複的編號,越高的板子編號越小。和以上兩個子問題相關的就只有板子的編號。

狀態:人人為我型遞推,(什麼是人人為我。人人為我型遞推是指從乙個或多個狀態的值來求出此狀態的值,用它周圍的                        點來求他的值)。

注意我為人人型遞推(用乙個「值」已知的狀態,求出其他多個狀態的值。用它的值來更新它周圍的點的值)

思路偽碼描述:

if(板子左端下方無別的板子)

else(板子k左端正下方的編號是m)

這道題很不錯,但是我找bug找不出來。大括號加錯了,我哭了,找bug找了好久。

#include#include#includeusing namespace std;

const int maxn=1001;

const int inf=0x3f3f3f;

int dp[maxn][maxn];

struct point

a[maxn+10];

int n,mmax;

bool cmp(point a,point b)

void rightmintime(int i)//右邊為起點

else

dp[i][1]=a[i].h;

}int shortesttime()

a[0].h=0;

a[0].lx=-20000;

a[0].rx=20000;

sort(a,a+n+1,cmp);

cout《給定兩個序列x=和y=找出x和y的乙個最長公共子串行。

如果暴力搜尋的話是2^m階,指數階複雜度會很高。

假設已知zk是xm和yn的最長公共子串行。

dp[i][j]=  dp[i-1][j-1]+1  (x=y)    max(dp[i-1][j],dp[i][j-1]).

poj - 1458 

#include#include#include#includeusing namespace std;

const int maxn=1010;

int dp[maxn][maxn];

char str1[maxn];

char str2[maxn];

int main()

else}}

for(int i=1;i<=len1;i++)

}printf("%d\n",answer);

} return 0;

}

這道題是最基礎的題目,真的很簡單,直接運用模型就可以。注意邊界情況,當str1=str2時是str[i-1]==str2[i-1]時dp[i][j]=dp[i-1][j-1]+1, 不能是str1[i]=str2[i]此時就不能保證dp[i-1][j-1]是否有意義。

#include#include#include#includeusing namespace std;

const int maxn=1001;

int dp[maxn],a[maxn];

int main()

for(int i=0;ia[j])}}

for(int i=0;i注意例如2 7 1 5 6 4 3 8 9這個序列,遍歷後dp[i]=max(dp[j]+1,dp[i])的條件是後面的比前面的大才會加一,否則就是以前的1,注意初始化為1,而不是0,因為就算後面的都不滿足條件,那也至少有乙個滿足條件。

#include#include#include#includeusing namespace std;

const int maxn=1001;

int dp[maxn],a[maxn];

int main()

for(int i=0;ia[j])}}

for(int i=0;i最大連續子串行和。第一步:確定狀態 dp[i]表示以a[i]為末尾的最大連續子串行的大小 第二步:確定狀態轉移方程 ①最大子串行和是a[i]本身。  dp[i] = a[i]; ②從前面某個a[k]到a[i],最大子串行和為前乙個最大子串行和加a[i]     dp[i] = dp[i - 1] + a[i]; 假設當前數字為a[i]    則 dp[i] = max 第三步:確定程式實現方式 dp[0] = a[0]; for(int i = 1;i < n; i++).

這道題是這種型別的基礎問題。

#include#include#include#includeusing namespace std;

const int maxn=1001;

int dp[maxn];

int a[maxn];

int main()

for(int i=0;ia[j])}}

for(int i=0;i好好刷題,具體可以參考kuangbin訓練專題。

前幾天一直在學dp,學了一段時間轉到了搜尋,感覺自己搜尋很薄弱,沒有系統的練題,很多題目很多題型就沒有做過,**能力也不強,這一周多的訓練感覺還行,只是自己太過於依賴題解,忽視了自我的思索過程。這一點一定要改,西安邀請賽在即,自己要加把勁啊,不會的還是太多,天賦不如人還沒有很努力說的就是我了。

DP基礎(線性DP)總結

前言 雖然確實有點基礎.但凡事得腳踏實地地做,基礎不牢,地動山搖,嗯!dp方程 dp i max 複雜度 o n 2 法一 資料結構無腦暴力優化 以a i 為陣列下標,從1到a i 訪問最大值,再加一,進行更新 法二 設h k 表示dp值為k的最長上公升子串行的最小值 有點貪心在裡面 顯然h k h...

簡單線性DP總結

首先 動態規劃適用的條件是該問題有最優子結構 無後效性 通過每個最優子結構狀態的遞推可以推出整體的最優解 對這些基本概念的理解既要理性也要一點點感性 dp問題解決順序是 1 確定狀態 通過最後一步將問題轉化為規模更小的子問題 2 轉移方程 3 初始條件與邊界情況 4 計算順序 其中前兩步是十分重要的...

線性DP基礎 acwing 動態規劃

注意點 1 其實就是講所有走每一步的時候求大致值就好,然後這個值又會對下面進行影響,就像自己思考問題一樣 2 然後就是需要注意一下邊界問題,因為我們這邊求最大值,所以需要對邊界進行初始化 最長上公升子串行理解 1 有一說一,樣板題,很快就容易,就是當前這個值可以由前面 轉過來然後max最大長度就行,...