算法学习笔记4-动态规划-背包问题
2017-09-11 18:13
141 查看
动态规划(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。
这样,每个阶段作出决策,我们就能得到最终问题的解。
上面例子的具体代码实现如下:
#include<iostream> #include<vector> #include<algorithm> using namespace std; int main() { int n; vector<int>v; vector<int>::iterator it; cin>>n; int *a=new int ; int *dp=new int {1}; for(int i=0;i<n;i++) cout<<dp[i]<<" "; cout<<endl; for(int i=0;i<n;i++) cin>>a[i]; for(int i=1;i<n;i++) { for(int j=0;j<i;j++) { if(a[j]<a[i]) dp[i]=max(dp[i],dp[j]+1); } } cout<<dp[n-1]<<endl; for(int i=0;i<n;i++) cout<<dp[i]<<" "; cout<<endl; delete []a; delete []dp; return 0; }
下面给出几个实际问题:
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背包问题与完全背包问题C++实现 动态规划
- 编程算法 - 背包问题(三种动态规划) 代码(C)
- 动态规划之 0-1背包问题及改进
- c++实现0-1背包问题完整源码(动态规划实现)
- 0-1背包问题,poj 3624 Charm Bracelet动态规划-解题报告,增加最优路径构建
- 动态规划(0-1背包问题)
- java 动态规划 背包问题
- 动态规划解决背包问题
- 【动态规划】从子集和问题到背包问题
- 完全背包问题(动态规划)(完全背包)
- 动态规划(背包问题)
- 动态规划之背包问题
- 【动态规划】三种基本背包问题
- 动态规划6-背包问题+记忆递归
- POJ 3132 Sum of Different Primes 动态规划 DP 0-1背包问题
- 动态规划--背包问题
- 动态规划 背包问题
- 0-1背包问题(动态规划)