...通过暴力手推得到的一点点感觉
动态规划是相对于贪心算法的一种取得最优解的算法,通过对每一步的取舍判断从 0 推到所拥有的第 n 件物品,每次判断可以列写出状态转移方程,通过记忆化相对暴力地取得最优解,如果有 n 件物品,容量为 m 的背包,则时间复杂度为 O(n*m)
状态转移方程如下:
for(int i=1;i<=n;i++) for(int j=0;j<=m0;j++) { if(j>=w[i]) { dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]); } else { dp[i][j]=dp[i-1][j]; } }
程序如下:
#include "iostream" #include "stdio.h" using namespace std; int w[105],v[105]; int dp[105][1005]; int main() { int n,m; scanf("%d%d",&m,&n); for(int i=1;i<=n;i++) { scanf("%d%d",&w[i],&v[i]); } for(int i=1;i<=n;i++) for(int j=0;j<=m;j++) { if(j>=w[i]) { dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]); } else { dp[i][j]=dp[i-1][j]; } } printf("%d",dp[n][m]); return 0; }
考虑使用动态规划时,应先判断是否满足动态规划所需要的两个特性:
- 无后效性:简单来说就是过去与未来无关,只需要知道过去所取得最优解的结果,对于怎么取得的并不关心(比如本题中取得 f(3,5)=7时,只知道7是由 f ( 2 , 2 ) + v [ 3 ] = 3 + 4 = 7,并不关心过去的 f(2,2)时怎么得来的;
- 最优子结构性:即“大问题的最优解可以由小问题的最优解推出”(比如本题中得到的每一个 f ( i , j )都是判断是否舍去前一个 i 所带的信息
题目可以试做洛谷1048采药:https://www.luogu.org/problemnew/show/P1048
据说使用二维数组的空间复杂度太高,数据小大就会爆内存,因此便有一维数组的dp:
核心代码:
for(int i=1;i<=m;i++) for(int j=t;j>=0;j--) if(j>=w[i]) dp[j]=max(dp[j-w[i]]+val[i], dp[j]); else dp[j]=dp[j];
正确性证明 :我还不会 :)谁来教教我orz