校内集训的第二天,讲解了bfs、dfs和dp。
今天的重点主要是01背包问题,这里就简单谈谈一种理解得比较好的做法。
读完题后可知,本题与应用于贪心算法中的背包问题有本质上的不同,那就是每件物品带有自己的权重,常规的贪心思路不可行,因此要借助动态规划来实现。
大体思路为将当前问题通过类似于递归的思路分解为若干子问题进行求解。
而代码实现时每个子问题要借助“状态”来进行独立解决,应用与本题,可以定义状态dp[i][j]以j为容量为放入前i个物品(按i从小到大的顺序)的最大价值。
将给出的物品价值从大到小进行排序,i=1时,放入第一个物品即为最优。而从第二个开始,每个物品有两种选择方法:
一种是选择第二个物品放入,另一种还是选择前面的物品;
由此得出动态转移方程:dp[i][j] = max(dp[i-1][j-w[i]])+v[i],dp[i-1][j])
当然这存在一个前提:背包的空间足够放下两个物品
而若是不满足这个条件,那么只能选择前面的物品:dp[i][j]=dp[i-1][j]
#include <iostream> #include <cstdio> using namespace std; int w[105]; int val[105]; int dp[105][1005]; int main() { int t,m,res=-1; scanf("%d%d",&t,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&w[i],&val[i]); } for(int i=1;i<=m;i++) for(int j=t;j>=0;j--) { if(j>=w[i]) {dp[i][j]=max(dp[i-1][j-w[i]]+val[i],dp[i-1][j]);} else {dp[i][j]=dp[i-1][j];} } printf("%d",dp[m][t]); return 0; }