动态规划,简单来讲就是寻找最优解的过程。在这其中的背包动态又分为0 1 背 包和完 全 背 包。
它们的区别在于:01背包问题每个物品只能被挑选一次,所以每次需要讨论的对象是下一个;
而完全背包问题每个物品可以被挑选多次,所以每次需要讨论的对象还是本身。
一道简单的例题帮助我们理解01背包:
中秋买了好多好吃的特别开心的金明
金明有n元买m个物品,使每件物品的价值(价值=价格*重要度)总和最大。
设第j件物品的价格为v,重要度为p
输入
n m(其中n(<30000)表示总钱数,m(<25)为希望购买物品的个数。)
从第2行到第m+1行,每行有2个非负整数
v,p(其中v表示该物品的价格(v<=10000),p表示该物品的重要度(1~5))
输出
输出只有一个正整数,为不超过总钱数的物品的价值总和的最大值(<100000000)
样例输入
1000 5
800 2
400 5
300 5
400 3
200 2
样例输出
3900
要使每件物品的价值总和最大,且不超过总钱数的物品的价值总和的最大值,我们可以构造一个二维数组dp[i][j],因为不需要恰好装满,所以初始化为dp都为0,然后数组表示的是对于前i件商品来说不超过j元的最优解
主要公式就是它:dp[i][j]=max(dp[i-1][j],dp[i-1][j-v[i]]+w[i])
#include <iostream>
#include<cstdio>
using namespace std;
struct Bag//结构体
{
int v;//v为价格
int p;//p为重要度
int value;//存放价格与件数的乘积
};
Bag bag[1010];
int dp[110][10010];
int main()
{
int n,m;//n为总钱数,m为希望购买物品个数
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>bag[i].v>>bag[i].p;
bag[i].value=bag[i].v*bag[i].p;
}
for(int i=1;i<=m;i++)
{
for(int j=n;j>=0;j--)
{
if(j>=bag[i].v)//如果能装下,就判断是否要装
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-bag[i].v]+bag[i].value);
}
else//装不下直接跳过
{
dp[i][j]=dp[i-1][j];
}
}
}
cout<<dp[m][n]<<endl;
return 0;
}
搜索到的01背包模板
无优化:
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
f[i][c]=f[i-1][c];
if(c>=w[i])
f[i][c]=max(f[i][c],f[i-1][c-w[i]]+v[i]);
}
}
---------------------
本文来自 SunPeishuai 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/SunPeishuai/article/details/80623473?utm_source=copy
一维数组优化:
for(int i=1;i<=n;i++)
{
for(int c=m;c>=0;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
---------------------
本文来自 SunPeishuai 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/SunPeishuai/article/details/80623473?utm_source=copy
更进一步的常数优化:
for(int i=1;i<=n;i++)
{
sumw+=w[i];
bound=max(m-sumw,w[i]);
for(int c=m;c>=bound;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
---------------------
本文来自 SunPeishuai 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/SunPeishuai/article/details/80623473?utm_source=copy