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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法-动态规划(01背包)

發布時間:2024/8/26 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法-动态规划(01背包) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近閑來無事,學學算法。

什么是動態規劃,我們要如何描述它?

動態規劃算法通常基于一個遞推公式及一個或多個初始狀態。當前子問題的解將由上一次子問題的解推出。使用動態規劃來解題只需要多項式時間復雜度,因此它比回溯法、暴力法等要快許多。

這里所說的子問題并不一定指前一個問題的解

比如說1+2+3+。。。+100,我們這里可以sum[i]+100來求出總和,而sum[i]是1加到i的總和,這個問題就是1加到99的子問題再加上100就得到。

動態規劃則并非是如此,它可能跟前面所有的子問題的某個解有聯系,舉個例子:

如果我們有面值為1元、3元和5元的硬幣若干枚,如何用最少的硬幣湊夠11元?

(表面上這道題可以用貪心算法,但貪心算法無法保證可以求出解,比如1元換成2元的時候)

首先我們思考一個問題,如何用最少的硬幣湊夠i元(i<11)?為什么要這么問呢?兩個原因:1.當我們遇到一個大問題時,總是習慣把問題的 規模變小,這樣便于分析討論。 2.這個規模變小后的問題和原來的問題是同質的,除了規模變小,其它的都是一樣的,本質上它還是同一個問題(規模變小后的問題其實是原問題的子問題)。

好了,讓我們從最小的i開始吧。當i=0,即我們需要多少個硬幣來湊夠0元。由于1,3,5都大于0,即沒有比0小的幣值,因此湊夠0元我們最少需 要0個硬幣。 (這個分析很傻是不是?別著急,這個思路有利于我們理清動態規劃究竟在做些什么。) 這時候我們發現用一個標記來表示這句“湊夠0元我們最少需要0個硬幣。”會比較方便,如果一直用純文字來表述,不出一會兒你就會覺得很繞了。那么,我們用 d(i)=j來表示湊夠i元最少需要j個硬幣。于是我們已經得到了d(0)=0,表示湊夠0元最小需要0個硬幣。當i=1時,只有面值為1元的硬幣可用, 因此我們拿起一個面值為1的硬幣,接下來只需要湊夠0元即可,而這個是已經知道答案的,即d(0)=0。所 以,d(1)=d(1-1)+1=d(0)+1=0+1=1。當i=2時,仍然只有面值為1的硬幣可用,于是我拿起一個面值為1的硬幣,接下來我只需要再 湊夠2-1=1元即可(記得要用最小的硬幣數量),而這個答案也已經知道了。所以d(2)=d(2-1)+1=d(1)+1=1+1=2。一直到這里,你 都可能會覺得,好無聊,感覺像做小學生的題目似的。因為我們一直都只能操作面值為1的硬幣!耐心點,讓我們看看i=3時的情況。當i=3時,我們能用的硬 幣就有兩種了:1元的和3元的( 5元的仍然沒用,因為你需要湊的數目是3元!5元太多了親)。既然能用的硬幣有兩種,我就有兩種方案。如果我拿了一個1元的硬幣,我的目標就變為了:湊夠 3-1=2元需要的最少硬幣數量。即d(3)=d(3-1)+1=d(2)+1=2+1=3。這個方案說的是,我拿3個1元的硬幣;第二種方案是我拿起一 個3元的硬幣,我的目標就變成:湊夠3-3=0元需要的最少硬幣數量。即d(3)=d(3-3)+1=d(0)+1=0+1=1. 這個方案說的是,我拿1個3元的硬幣,這里d(3)值跟d(2)是沒有關系的,如果你還不理解,下面我們結合01背包來說明。好了,這兩種方案哪種更優呢?記得我們可是要用最少的硬幣數量來湊夠3元的。所以,選擇d(3)=1,怎么來的呢? 具體是這樣得到的:d(3)=min{d(3-1)+1, d(3-3)+1}。

狀態和狀態轉移方程

從以上的文字中,我們要抽出動態規劃里非常重要的兩個概念:狀態和狀態轉移方程。

狀態:就是上面d(3)d(2)等,抽象d(i);

狀態轉移方程:d(3)=min{d(3-1)+1, d(3-3)+1},抽象d(i)=min{ d(i-vj)+1 },其中i-vj >=0,vj表示第j個硬幣的面值;

01背包問題

問題描述:有N件物品和一個容量為V的背包。第i件物品的體積是c[i],價值是w[i]。求解將哪些物品裝入背包可使價值總和最大。

狀態轉移方程:f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}

這個方程非常重要,基本上所有跟背包相關的問題的方程都是由它衍生出來的
偽碼:
??for i=1..N
???for v=V..0
????f[v]=max{f[v],f[v-c[i]]+w[i]};
如果不放第i件物品,那么問題就轉化為“前i-1件物品放入容量為v的背包中”,
價值為f[i-1][v];
如果放第i件物品,那么問題就轉化為“前i-1件物品放入剩下的容量為v-c[i]的背包中”,
此時能獲得的最大價值就是f[i-1][v-c[i]]再加上通過放入第i件物品獲得的價值w[i]。

如果一開始看01背包這里最容易混淆,我就是在這里迷糊好久,要特別如果不明白要特別注意上面粗體的字,它是先放第i件,然后剩下容量再放前面i-1件,然而剩下容量所裝的物品,我們前面都已求出,下面,讓我們根據代碼來理解;

Input輸入的第一行有兩個整數T(1 <= T <= 1000)和M(1 <= M <= 100),用一個空格隔開,T代表背包容量,M代表物品數目。接下來的M行每行包括兩個在1到100之間(包括1和100)的整 數,分別表示每個物品的體積和價值。
Output輸出包括一行,這一行只包含一個整數,裝入背包可使價值總和最大。
Sample Input
70 3
71 100
69 1
1 2
Sample Output
3

#include<iostream> # include<cstring> # define max(a,b) a>b?a:b using namespace std; int main() { int dp[101][1001],m,T,w[101],val[101],i,j; cin>>T>>m; for(i=1;i<=m;i++) cin>>w[i]>>val[i]; memset(dp,0,sizeof(dp)); for(i=1;i<=m;i++)
{ for(j=0;j<=T;j++)//j相當于上面說的V-c[i],這里的循環都是為后面解準備的 { if(j>=w[i]) dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+val[i]);//放還是不放的選擇 else dp[i][j]=dp[i-1][j];
  cout<<dp[i][j]<<" "; }
cout<<endl;
} cout<<dp[m][T]<<endl; return 0; }

這里就測試一下,
10 4
5 10
8 16
5 5
10 10

如果要符合上面題目輸出要求,把紅色代碼去掉

?

轉載于:https://www.cnblogs.com/lsgsanxiao/p/5195446.html

總結

以上是生活随笔為你收集整理的算法-动态规划(01背包)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。