日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

经典DP

發(fā)布時(shí)間:2023/12/20 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 经典DP 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.背包問(wèn)題

(1)01背包

從n個(gè)重量和價(jià)值分別為wi,vi的物品,從中選出不超過(guò)W的物品,每種物品僅有一件,求所有方案中V的最大值。

最樸素最簡(jiǎn)單也最費(fèi)時(shí)的方法:O(2^n) int rec(int i,int j)//從第i個(gè)開始挑選總重小于j的部分

遞歸 ?遞歸終止條件:i==n ?return 0;

??????遞歸分支:① j<wi res=rec(i+1,j); ?//無(wú)法挑選,看下一個(gè)

????????????????② res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]))//挑選,不挑選,選其中大的

分析:遞歸搜索深度→n,每層兩次分支(選與不選),有重復(fù)計(jì)算

優(yōu)化:記錄每次遞歸的結(jié)果(記憶化搜索)

?

Int dp[MAX_N][MAX_N];

遞歸 int rec(int i,int j)

????初始條件:memset(dp,-1,sizeof(dp));

終止條件:①dp[i][j]>=0 returndp[i][j]//已計(jì)算過(guò)

②i==n return 0;

????遞歸分支:① j<wi res=rec(i+1,j); ?//無(wú)法挑選,看下一個(gè)

????????????????② res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]))//挑選,不挑選,選其中大的

分析及remark:復(fù)雜度O(nW)

???數(shù)組初始化:①memset(type *arrary,figure,sizeof(arrary))

? ? ? ? ? ? ? ? ? ? ? 只能填充(0,+-1,0x3f3f3f3f),其他值不可以?

? ? ? ? ? ? ? ? ? ? ? memset按照1字節(jié)為單位對(duì)內(nèi)存填充,-1的二進(jìn)制每一位均為1

? ? ? ? ? ? ? ? ? ? ? ②fill(type* arrary,type *arrary+n,figure) 可賦值任意值

????遞歸 ?

?↓↓↓↓↓↓ ? ? ? ? ? ? ? ?? for(int i=n-1;i>=0;i--)?//

遞推(雙重循環(huán)) ??????????for(int j=0;j<=w;j++)

? ? ? ? ? ? ? ? ? ? ? ? ? { if(j<w[i]) dp[i][j]=dp[i+1][j]; //不選

?????????????????????????else dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);}

其他3種遞推寫法:(來(lái)源:《挑戰(zhàn)程序設(shè)計(jì)競(jìng)賽》)

?

(2)完全背包

遞推關(guān)系1:(3重循環(huán),有重復(fù)計(jì)算)復(fù)雜度O(nW^2)

For(int i=0;i<n;i++)

?For(int j=0;j<=w;j++)

??For(int k=0;k*w[i]<=j;k++)

? Dp[i+1][j]=max(dp[i+1][j],dp[i+1][j-k*w[i]]+k*v[i])

優(yōu)化:(左上→右下 ?變?yōu)?左→右)

Dp數(shù)組初始化為0

For(int i=0;i<n;i++)

?For(int j=0;j<=w;j++)

{

?If(j<w[i]) dp[i+1][j]=dp[i][j];

?Else ?dp[i+1][j]=max(dp[i][j],dp[i+1][j-w[i]]+v[i])

}???????????只有這里與01背包不同,前j個(gè)已更新過(guò),可直接用

?

進(jìn)一步優(yōu)化:用一個(gè)數(shù)組實(shí)現(xiàn),只需要記錄當(dāng)前最優(yōu)狀態(tài)

比較01背包與完全背包(循環(huán)方向不同)

?

2.LCS(Longest common subsequence)

?

dp[n][m]即為所求

for(int i=0;i<n;i++)

??for(int j=0;j<m;j++)

{

??if(s[i]==t[i])

???dp[i+1][j+1]=dp[i][j]+1;

else

???dp[i+1][j+1]=max(dp[i+1][j],dp[i][j+1])

}

?

3.LIS(Longest Increasing subsequence)

?

dp[i]:以ai為結(jié)尾的最長(zhǎng)上升子序列長(zhǎng)度

dp[i]=max{1,dp[i]+1|j<i且aj<ai}

O(n^2)

int res;

for(int i=0;i<n;i++)

?{

? dp[i]=1;

for(int j=0;j<i;j++)

? if(a[j]<a[i]) ? ? ? ? ? ?? //每存在aj<ai&&j<i,dp[i]更新一次

?? dp[i]=max{dp[i],dp[j]+1};

}

res=max{dp[i]|0<=i<n}

Remark:

其他方法:

可以用lower_bound();

?? dp[i]:長(zhǎng)度為i+1的上升子列中末尾元素的最小值(不存在的話為inf)

dp[max_n]初始化為inf,按順序逐個(gè)考慮數(shù)列的元素,對(duì)于每個(gè)ai,如果i=0||dp[i-1]<ai,就用dp[i]=min(dp[i],ai)更新,最終找出使得dp[i]<inf的最大的i+1即為結(jié)果。DP直接實(shí)現(xiàn),可以在O(n^2)的時(shí)間內(nèi)給出結(jié)果,但可以進(jìn)一步優(yōu)化,dp數(shù)組中除inf之外是單調(diào)遞增的,對(duì)于每個(gè)ai最多有一次更新,更新的位置可用二分的方法優(yōu)化,時(shí)間復(fù)雜度可以降低到O(nlogn)

int dp[max_n]

void solve()

{

? fill(dp,dp+n,inf);

? for(int i=0;i<n;i++)

? ? *lower_bound(dp,dp+n,a[i])=a[i];

? res=lower_bound(dp,dp+n,inf)-dp;

}

// lower_bound()可以從已排好序的a中利用二分搜索找出滿足ai>=k的ai的最小的指針,類似的還有upper_bound,找出的為ai>k的最小指針

//求n個(gè)有序數(shù)組a中k的個(gè)數(shù),可以用:upper_bound(a,a+n,k)-lower_bound(a,a+n,k);

轉(zhuǎn)載于:https://www.cnblogs.com/Egoist-/p/7391224.html

總結(jié)

以上是生活随笔為你收集整理的经典DP的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。