动态规划
来源:互联网 发布:徐州淘宝产业链 编辑:程序博客网 时间:2024/05/22 15:44
本文章参考《挑战程序设计竞赛》的2.3节“记录结构再利用的动态规划”。
01背包问题
有n个重量和价值分别为wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
for example:n=4,(w,v)={(2,3),(1,2),(3,4),(2,2)},W=5。
对于解决这个问题,先尝试用最朴素的办法针对每个物品是否放入背包进行搜索试试。代码如下:
<span style="font-family:Microsoft YaHei;">//输入int n,W;int w[MAX_N],v[MAX_N];//从第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;}void solve(){ printf("%d\n",rec(0,W));}</span>这种方法的搜索深度是n,且每一层搜索都需要两次分支,最坏就需要O(2^n)的时间。递归调用情况如图所示:
从图中可以看出,rec以(3,2)为参数调用了两次。如果参数相同,返回的结果也应该相同,于是出现了重复计算的情况。现在把第一次计算时的结果记录下来,省略掉重复计算,代码如下:
<span style="font-family:Microsoft YaHei;">int dp[MAX_N+1][MAX_W+1]; //记忆化数组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]); //将结果记录在数组中 return dp[i][j]=res;}void solve(){ //用-1表示尚未计算过,初始化整个数组 memset(dp,-1,sizeof(dp)); printf("%d\n",rec(0,W));}</span>dp[i][j]:=从第i个物品开始挑选总重小于j时,总价值的最大值
dp[n][j]=0
根据上述递推公式直接将各项的值计算出来。代码如下:
<span style="font-family:Microsoft YaHei;">int dp[MAX_N+1][MAX_W+1]; //DP数组void solve(){ for(int i=n-1;i>=0;i--) { for(int j=0;j<=W;j++) { if(w[i]>j) dp[i][j]=dp[i+1][j]; else dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]); } } printf("%d\n",dp[0][W]);}</span>
0 0
- 动态规划!!!动态规划!!!
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- ios 时间与字符串相互转换,包含时区的转换
- 黑马程序员——生产者和消费者问题
- jQuery筛选器children()
- Fragment的使用
- 115个Java面试题和答案——终极列表(上)
- 动态规划
- 115个Java面试题和答案——终极列表(下)
- NYOJ 题目214 单调递增子序列(二)(动态规划,二分)
- linux内核链表笔记
- switch case 语句要注意!!!
- 用位运算实现四则运算之加减乘除(用位运算求一个数的1/3)
- 自定义vector
- EOJ 1855 【贪心】 【优先队列】
- 【矩阵相交】矩形相交以及求出相交的区域的原理解析