01揹包問題
有n個重量和價值分別爲wi,vi的物品,從這些物品中挑選出總重量不插過W的物品,求所有挑選方案中價值總和的最大值
限制條件
1<=n<=100
1<=wi,vi<=100
1<=W<=10000
常規通法DFS
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1<<23
#define mod 1e9+7
typedef long long LL;
typedef long long ll;
int n;//物品數量
int w[100+5];//物品質量
int v[100+5];//物品價值
int W;//揹包總總質量
//i代表物品編號,j代表揹包剩餘質量
int dfs(int i,int j)
{
int res;
if(i==n)
{
//已經沒有剩餘的物品了
res=0;
}
else if(j<w[i])
{
//揹包可利用價值小於該物品價值
res=dfs(i+1,j);
}
else
{
// 不挑選 挑選
res=max(dfs(i+1,j),dfs(i+1,j-w[i])+v[i]);
}
return res;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%d%d",&w[i],&v[i]);
}
scanf("%d",&W);
printf("%d\n",dfs(0,W));
}
return 0;
}
分析:在此做法中,我們因爲沒有進行剪枝優化,所以進行了多次對同一狀態進行搜索,因此我們可以通過利用一個數組dp[i][j]進行存儲狀態,即所謂的記憶化搜索
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1<<23
#define mod 1e9+7
typedef long long LL;
typedef long long ll;
int n;//物品數量
int w[100+5];//物品質量
int v[100+5];//物品價值
int W;//揹包總總質量
int dp[100+5][10000+5];//i代表物品編號,j代表揹包剩餘質量,依據題目限制條件寫出數組範圍
//i代表物品編號,j代表揹包剩餘質量
int dfs(int i,int j)
{
int res;
if(dp[i][j]>=0)
{
return dp[i][j];
}
if(i==n)
{
//已經沒有剩餘的物品了
res=0;
}
else if(j<w[i])
{
//揹包可利用價值小於該物品價值
res=dfs(i+1,j);
}
else
{
// 不挑選 挑選
res=max(dfs(i+1,j),dfs(i+1,j-w[i])+v[i]);
}
return dp[i][j]=res;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
//初始化dp數組
memset(dp,-1,sizeof(dp));
for(int i=0; i<n; i++)
{
scanf("%d%d",&w[i],&v[i]);
}
scanf("%d",&W);
printf("%d\n",dfs(0,W));
}
return 0;
}
現在我們研究存儲狀態的記憶化數組,設dp[i][j]存儲的是此刻此時揹包中左右物品的價值總和,i代表的是我當前已經記錄的狀態,i+1代表的是揹包此時所要面對的物品的編號(假設我是揹包,我已經經歷過了i號,現在面對的是i+1號,我到底是取還是不取i+1號呢?)
所以我們可以定義
dp[i+1][j]:從0到i這i+1個物品選出總重量不超過j的物品時的總價值
dp[0][j]=0
所以dp[i+1][j]存在兩種狀態
第一:dp[i+1][j]=dp[i][j] (j<w[i])代表當前揹包剩餘重量已經無法滿足存儲當前物品重量
第二:dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i])(結合記憶化搜索,可以理解爲在選擇與不選擇這個物品進行一下對比
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define INF 1<<23
#define mod 1e9+7
typedef long long LL;
typedef long long ll;
int n;//物品數量
int w[100+5];//物品質量
int v[100+5];//物品價值
int W;//揹包總總質量
int dp[100+5][10000+5];//i代表物品編號,j代表揹包剩餘質量,依據題目限制條件寫出數組範圍
void solve()
{
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][j-w[i]]+v[i]);
}
}
}
printf("%d\n",dp[n][W]);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
//初始化dp數組
memset(dp,0,sizeof(dp));
for(int i=0; i<n; i++)
{
scanf("%d%d",&w[i],&v[i]);
}
scanf("%d",&W);
solve();
}
return 0;
}