算法学习笔记4-动态规划-背包问题
2017-08-15 16:06
169 查看
动态规划(Dynamic Programming)
动态规划是一种求解最优化问题的方法,因为它没有一个确定的数学表达式,或者是明确的解题步骤,说起来会比较抽象,我们只能在实际题目中体会。首先说几个概念吧:
这里先给个栗子:
给定一个整数序列,求这个序列的最长上升子序列,子序列可以是不连续的。比如对于序列(1,7,2,8,3,4),它的子序列是(1,2,3,4)。
1. 阶段
动态规划含有一种递推的思想,如果一个问题可以分成不同的“阶段”,上一个阶段的决策直接影响下一个阶段,我们就可以考虑使用动态规划,依次求出每一个阶段的最优解,直到解决整个问题,也就是拆分问题。
比如上面的例子,我们可以把问题拆解为求以k结尾的序列的最长子序列,也就是分别求序列{[1],[1,7],[1,7,2],[1,7,2,8],[1,7,2,8,3],[1,7,2,8,3,4]}的最长上升子序列。
2. 状态
每一个阶段的客观条件我们称为“状态”。一个阶段可能有一个或多个状态,我们可以用一个状态变量来表示,比如上面每一个阶段可以表示为{[1],[1,7],[1,7,2],[1,7,2,8],[1,7,2,8,3],[1,7,2,8,3,4]}。
这里我们可以看到,其实阶段和状态有时候是不区分的。
3. 决策(状态转移方程)
从一个阶段演变到下一个阶段,叫做“决策”,也就是说不同的决策可能会演变到不同的阶段。
而状态跟状态之间的关系式,叫“状态转移方程”,其实它影响了我们的决策,比如上面的例子,在选择数字1之后,下一步是选择7还是选择2,就需要决策,而如果我们的状态转移方程是F_i=min(A_i,A_i-1),那么我们就会选择较小的2。
这样,每个阶段作出决策,我们就能得到最终问题的解。
下面给出几个实际问题:
1. 背包问题
题目描述:辰辰是个很有潜能、天资聪颖的孩子,他的梦想是称为世界上最伟大的医师。 为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。 医师把他带到个到处都是草药的山洞里对他说: “孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。
我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 如果你是辰辰,你能完成这个任务吗?
输入描述:
输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),T代表总共能够用来采药的时间,M代表山洞里的草药的数目。 接下来的M行每行包括两个在1到100之间(包括1和100)的的整数,分别表示采摘某株草药的时间和这株草药的价值。
#coding = utf-8 #backpack problem/dynamic problem while True: try: time,m=raw_input().split() time=int(time) m=int(m) t=[]#time v=[]#value for i in xrange(m): t1,t2=raw_input().split() t1=int(t1) t2=int(t2) t.append(t1) v.append(t2) dp=[0 for i in range(time+1)] for i in xrange(m): for j in xrange(time,t[i]-1,-1): dp[j]=max(dp[j],dp[j-t[i]]+v[i]) print dp[time] except: break
2. 合唱团
题目描述:有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
输入描述:
每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
#coding=utf-8 n=input() a=list(raw_input().split()) a=[int(i) for i in a] ik,d=raw_input().split() ik=int(ik) d=int(d) #动态规划,用两个数组,保留一正一负两个结果 mx=[[0 for i in range(n)] for i in range(ik)] mn=[[0 for i in range(n)] for i in range(ik)] m=0 for i in range(n): mx[0][i]=mn[0][i]=a[i] for k in range(1,ik): for j in range(i-1,-1,-1): if i-j>d: break mx[k][i]=max(mx[k][i],max(mx[k-1][j]*a[i],mn[k-1][j]*a[i])) mn[k][i]=min(mn[k][i],min(mx[k-1][j]*a[i],mn[k-1][j]*a[i])) m=max(m,mx[ik-1][i]) print m
相关文章推荐
- 算法学习笔记4-动态规划-背包问题
- 动态规划0-1背包问题
- 51nod 多重背包问题(动态规划)
- 0-1背包问题 动态规划 算法入门经典
- 动态规划——切钢筋、矩阵链乘法、菲波拉契数列和背包问题
- 01背包问题回溯法和动态规划
- 动态规划的背包问题 (共六题)
- 0-1背包问题(动态规划)
- 【动态规划】完全背包问题
- 动态规划 - 0-1背包问题的算法优化
- Python动态规划计算0-1背包问题的最优值
- POJ 1276 Cash Machine -- 动态规划(背包问题)
- 动态规划(二维背包问题):UVAoj 473
- [转载]动态规划之0-1背包问题
- 动态规划小结——背包问题
- 简单0-1背包问题(算法类别:动态规划)
- 动态规划 背包问题 poj 1837 Balance
- 【笔记】【算法学习】【动态规划】背包问题总结(1)
- 动态规划——4 背包问题
- 0-1背包问题与完全背包问题C++实现 动态规划