HDU 2602 Bone Collector
大致意思:n個骨頭,不同骨頭價值和重量不同,知道揹包的容量s,求最大價值。
--------------------------------------------------------------------------------------------------------------------------------------------------
動態規劃先找出子問題,我們可以這樣考慮:在物品比較少,揹包容量比較小時怎麼解決?用一個數組dp[i][j]表示,在只有i個物品,容量爲j的情況下揹包問題的最優解,那麼當物品種類變大爲i+1時,最優解是什麼?第i+1個物品可以選擇放進揹包或者不放進揹包,假設放進揹包(前提是放得下),那麼dp[i+1][j]=dp[i][j-weight[i+1]+value[i+1];
如果不放進揹包,那麼dp[i+1][j]=dp[i][j]。放不下就是dp[i+1][j]=dp[i][j];
這就得出了狀態轉移方程:
dp[i+1][j]=max(dp[i][j],dp[i][j-weight[i+1]+value[i+1])
/**01揹包**/
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=1010;
int w[maxn];//重量
int v[maxn];//價值
int dp[maxn][maxn];
int n,s;
void slove()
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= s; j++)
{
if(j < w[i])///揹包容量比第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]);
cout << dp[i][j] << ' ';
}
cout << endl;
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(dp,0,sizeof(dp));
cin>>n>>s;
for(int i=1; i<=n; i++)
cin>>v[i];//價值
for(int i=1; i<=n; i++)
cin>>w[i];//重量
slove();
cout << dp[n][s] << endl;
}
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
上面計算 dp[i][j]可以看出,在計算 dp[i][j]時只使用了 dp[i-1][0……j],沒有使用其他子問題,因此在存儲子問題的解時,只存儲 dp[i-1]子問題的解即可。這樣可以用兩個一維數組解決,一個存儲子問題,一個存儲正在解決的子問題。再進一步思考,計算dp[i][j]時只使用了 dp[i-1][0……j],沒有使用dp[i-1][j+1]這樣的話,我們先計算j的循環時,讓j=M……1,只使用一個一維數組即可。這就得出了狀態轉移方程:
dp[j]=max(dp[j],dp[j-weight[i]+value[i]) ;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[1010],weight[1010],value[1010];//全局變量,自動清0;
int main()
{
int t,n,m,i,j;
cin>>t;
while(t--)
{
memset(dp,0,sizeof(dp));//記得清0;
cin>>n>>m;
for(i=1;i<=n;i++)
cin>>value[i];
for(i=1;i<=n;i++)
cin>>weight[i];
for(i=1;i<=n;i++)
{
for(j=m;j>=weight[i];j--)
{
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
}
}
cout<<dp[m]<<endl;
}
return 0;
}