动态规划之背包问题
有n个重量和价值分别为Wi,Vi的物品。从这些物品中挑选总重量不超过W的物品,求所得的挑选方案中价值总和的最大值。
这是一个著名的01背包问题。
输入:
n = 4
(w,v) = {(2,3),(1,2),(3,4),(2,2)}
W = 5
输出:
7
方案一:
#include"stdio.h"
#define MAX_N 100
#define max(a,b) (a)>(b)?a:b
int n = 4,W=5;
int w[MAX_N]={2,1,3,2}, v[MAX_N]={3,2,4,2};
//从第i个物品开始挑选总重量小于j的部分
int rec(int i,int j)
{
int res;
if(i==n)
{
//已经没有剩余物品了
res = 0;
}
else if(j<w[i])
{
//无法挑选这个物品
res = rec(i+1,j);
}
else
{
//挑选和不挑选两种情况都尝试一下
res = max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
}
return res;
}
int main()
{
printf("%d",rec(0,5));
return 0;
}
但是,这里有一个问题,就是重复计算次数太多。改进如下:
#include"stdio.h"
#define MAX_N 100
#define max(a,b) (a)>(b)?a:b
int dp[MAX_N+1][MAX_N+1];//记忆化数组
int n = 4,W=5;
int w[MAX_N]={2,1,3,2}, v[MAX_N]={3,2,4,2};
//从第i个物品开始挑选总重量小于j的部分
int rec(int i,int j)
{
if(dp[i][j]>=0)
return dp[i][j];
int res;
if(i==n)
{
res = 0;
}
else if(j<w[i])
{
res = rec(i+1,j);
}
else
{
res = max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
}
dp[i][j] = res;
return res;
}
int main()
{
memset(dp,-1,sizeof(dp));
printf("%d",rec(0,5));
return 0;
}
就是添加了动态数组这一句话,提升的性能确是很多的。
正面动态规划:
void solve()
{
dp[0][0]=0;
int i,j;
for(i=0;i<n;i++)
for(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",dp[n][W]);
}