动态规划之记忆化搜索(滑雪)
来源:互联网 发布:傻瓜软件下载 编辑:程序博客网 时间:2024/05/22 02:17
原文转载自:http://www.cnblogs.com/fu11211129/p/4276213.html
一. 动态规划
动态规划(dynamic programming),与“分治思想”有些相似,都是利用将问题分 为子问题,并通过合并子问题的解来获得整个问题的解。于“分治”的不同之处在 于,对于一个相同的子问题动态规划算法不会计算第二次,其实现原理是将每一个计算过的子问题的值保存在一个表中。
二. 记忆化搜索
我们常见的动态规划问题,比如流水线调度问题,矩阵链乘问题等等都是“一步接着一步解决的”,即规模为 i 的问题需要基于规模 i-1 的问题进行最优解选择,通常的递归模式为DP(i)=optimal{DP(i-1)}。而记忆化搜索本质上也是DP思想,当子问题A和子问题B存在子子问题C时,如果子子问题C的最优解已经被求出,那么子问题A或者是B只需要“查表”获得C的解,而不需要再算一遍C。记忆化搜索的DP模式比普通模式要“随意一些”,通常为DP(i)=optimal(DP(j)), j < i。
三. 滑雪问题
上图显示为R*C的雪场,R是行数,C是列数。圆圈内的数字表示的是雪场的海拔高度h,根据常识我们知道,滑雪只有从上往下滑行才可能滑的动,现在我们想要求出能够滑行的最长距离,上面的例子我们可以很直接判断出25-24-......-1这个顺时针方向螺旋的滑雪方式可以滑的最远。
那么这个问题如何用编程来实现呢?我们发现这是一个典型的递推,DP(i, j)表示从坐标(i,j)出发所能滑行的最大长度,且有:DP(i, j)=optimal{DP(i±1, j±1)}+1。下面貼上源代碼。
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int max_size=110;int R,C;int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};int h[max_size][max_size],dp[max_size][max_size];int inMap(int x,int y){ if(x>=0&&x<=R-1&&y>=0&&y<=C-1) return 1; return 0; } int max2(int a,int b,int c,int d){ return max(max(a,b),max(c,d));} int dfs(int i,int j){ int nx,ny,down=0,up=0,left=0,right=0; if(dp[i][j]) return dp[i][j]; nx=i+dir[0][0]; ny=j+dir[0][1]; if(inMap(nx,ny)){ if(h[i][j]>h[nx][ny]) up=dfs(nx,ny); } nx=i+dir[1][0]; ny=j+dir[1][1]; if(inMap(nx,ny)){ if(h[i][j]>h[nx][ny]) right=dfs(nx,ny); } nx=i+dir[2][0]; ny=j+dir[2][1]; if(inMap(nx,ny)){ if(h[i][j]>h[nx][ny]) down=dfs(nx,ny); } nx=i+dir[3][0]; ny=j+dir[3][1]; if(inMap(nx,ny)){ if(h[i][j]>h[nx][ny]) left=dfs(nx,ny); } dp[i][j]=max2(up,down,left,right)+1; return dp[i][j]; }int main(){ scanf("%d%d",&R,&C); memset(h,0,sizeof(h)); memset(dp,0,sizeof(dp)); for(int i=0;i<R;i++){ for(int j=0;j<C;j++){ scanf("%d",&h[i][j]); } } int ans=-1; for(int i=0;i<R;i++){ for(int j=0;j<C;j++){ ans=max(ans,dfs(i,j)); } } printf("%d\n",ans);}
四. 切棒子问题
给你一根长n英尺的棒子和一份关于该棒子的价目表如下(其中 i = 1,2,3,…,n),请问如何将这根棒子卖出最高的价格,可以对棒子进行切割。
这个题同样是可以利用DP记忆化搜索来实现的,递推公式为DP(n)=optimal{max{price(i)+DP(n-i)|1≤i≤n}}。实现代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int max_size=50; 6 const int inf=1<<30; 7 int price[max_size],dp[max_size]; 8 int n; 9 int dfs(int n){10 if(dp[n]) return dp[n];11 if(n==0) return 0;12 int mmax=-inf;13 for(int i=1;i<=n;i++){14 mmax=max(mmax,price[i]+dfs(n-i));15 }16 dp[n]=mmax;17 return dp[n];18 }19 int main(){20 while(scanf("%d",&n)!=EOF){21 for(int i=1;i<=n;i++) scanf("%d",&price[i]);22 printf("%d\n",dfs(n));23 }24 }
五. 01背包问题
问题描述: 有N件物品和一个重量为M的背包。(每种物品均只有一件)第i件物品的重量是w[i],价值是p[i]。求解将哪些物品装入背包可使价值总和最大。思路也很简单,直接看代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 const int max_size=50; 6 const int inf=1<<30; 7 int p[max_size],w[max_size],dp[max_size][max_size]; 8 int n,v; 9 int dfs(int i,int v){10 if(dp[i][v]) return dp[i][v];11 if(i==0||v<=0) return 0;12 if(w[i]>v) dp[i][v]=dfs(i-1,v);13 else dp[i][v]=max(dfs(i-1,v),dfs(i-1,v-w[i])+p[i]);14 return dp[i][v];15 }16 int main(){17 while(scanf("%d",&n)!=EOF){18 memset(dp,0,sizeof(dp));19 for(int i=1;i<=n;i++) scanf("%d",&p[i]);20 for(int i=1;i<=n;i++) scanf("%d",&w[i]);21 scanf("%d",&v);22 printf("%d\n",dfs(n,v));23 }24 }
六. 总结
通过前两个例子分析,我们可以得出DP记忆化搜索的算法模板(自己DIY的,大家可以选择参考)
1 dfs(problem a){2 if(a has been solved) 3 then: consult the record.4 else//get the optimal solution of problem a.5 divide the problem a into several sub-problems(a1,a2,...,ak)6 get the solution of problem a by dfs(a1),dfs(a2),...,dfs(ak).7 finally write the optimal solution into record.8 }
Description
1 2 3 4 516 17 18 19 615 24 25 20 714 23 22 21 813 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。
Input
Output
Sample Input
5 51 2 3 4 516 17 18 19 615 24 25 20 714 23 22 21 813 12 11 10 9
Sample Output
25
#include <iostream> #include <algorithm> using namespace std; int map[105][105], dp[105][105]; int n, m; int solve(int x, int y) { if (dp[x][y]) return dp[x][y]; int MAX = 1; int cur_height = map[x][y]; if (x + 1 <= n&&cur_height > map[x + 1][y]) { int tmp = solve(x + 1, y) + 1; MAX = max(MAX, tmp); } if (x - 1 > 0&&cur_height > map[x - 1][y]) { int tmp = solve(x - 1, y) + 1; MAX = max(MAX, tmp); } if (y + 1 <= m&&cur_height > map[x][y + 1]) { int tmp = solve(x, y + 1) + 1; MAX = max(MAX, tmp); } if (y - 1 > 0&&cur_height > map[x][y - 1]) { int tmp = solve(x, y - 1) + 1; MAX = max(MAX, tmp); } dp[x][y] = MAX; return MAX; } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> map[i][j]; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) solve(i, j); int ans = 1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) ans = max(ans, dp[i][j]); cout << ans << endl; return 0; }
- 动态规划之记忆化搜索(滑雪)
- POJ088滑雪(记忆化搜索|动态规划)
- POJ 1088 滑雪(动态规划+记忆化搜索)
- poj 1088 滑雪(动态规划:记忆化搜索)
- poj 1088 滑雪(记忆化搜索/动态规划)
- poj 1088 滑雪 动态规划(记忆化搜索)
- 记忆化搜索(DFS+动态规划)--滑雪
- POJ-1088-滑雪-解题报告-动态规划-记忆化搜索
- poj 1088 滑雪 动态规划 记忆化搜索
- poj1088滑雪,记忆搜索,动态规划问题
- 记忆化搜索算法之动态规划
- 滑雪 (记忆化搜索)
- 滑雪(记忆化搜索)
- 百炼-1088-滑雪-C语言-动态规划-记忆化搜索
- 动态规划(记忆化搜索)
- poj1088滑雪--dp之记忆化搜索
- 动态规划之从搜索到记忆化搜索到递推式
- 滑雪 记忆化搜索
- 页面DOM元素的scroll与offset相关属性
- LeetCode-Battleships in a Board
- Python3 循环语句
- gram_matrix
- 计蒜客 Query on a string (线段树)
- 动态规划之记忆化搜索(滑雪)
- RHEL7.2安装驱动
- [算法分析与设计] leetcode 每周一题: 126. Word Ladder II
- 2016ACM/ICPC亚洲区青岛站【solved:5 / 13】
- java虚拟机加载类机制
- 算法第四周Judge Route Circle[easy]
- MyEclipse搭建java Web项目开发环境
- U3D屏幕坐标,世界坐标,像素坐标之间的关系
- nginx的酷配置