动态规划小结

什么是动态规划:

   其本质就是利用申请的空间来记录每一个暴力搜索的计算结果,下次要用结果的时候就直接使用,而不是进行重复的递归过程。

1.动态规划学习步骤:

1)阅读题目找出所需的暴力求解方法(递归调用)。

注:要学会递归调用的关系。

(2)根据题目加入相应的记忆数组,来存储递归过程中访问过的结点。使其重复的过程大大减少。(记忆化的暴力求解方法)

(3)而后演变到有规律的进行访问,将访问的结点保存。知道得出结果。

(4)由于步骤三中访问过程是有规律的,使得进一步化简得到可能。在寻找好的方法(时间和空间)。


相关习题的练习:

  

2.动态规划的题目设计:

     1)此题目来源于北大POJ

        数字三角形(POJ1163)

    

在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的行数大于1小于等于100,数字为 0 - 99

输入格式:

    5      //表示三角形的行数    接下来输入三角形

    7

    3   8

    8   1   0

    2   7   4   4

    4   5   2   6   5

    要求输出最大和


分析思路:首先想到暴力搜索:

     Data[i][j]来存储第i行第j列的数Max_serch(x,y)表示从x行,y列到底地边个点的路径中,路径之和最大的。则可以通过Max_serch(0,0)递归得到。因为从Data[i][j]出发只能到Data[i+1][j]Data[i+1][j+1].递归关系式:

  

   (1)i或者j为底边行或者列,这就返回Data[i][j].

   (2)否则就Max_serch(i,j)=max(Max_serch(i+1,j),Max_serch(i+1,j+1))+Data[i][j]

代码:

int Max_serch(int x,int y){
    if(x==n-1||y==n-1){
    	return Data[x][y];
	}else{
		return   max(Max_serch(x+1,y),Max_serch(x+1,y+1))+Data[x][y];
	}
 }


动态过程:


 

此时访问的过程没有记忆化,所以会出现大量的重复搜索。

例如:当我们计算第二行2时候的Max_serch()会计算从7开始的Max_serch(),当我们计算第二行4时候的Max_serch()也会计算从7开始的Max_serch(),所以出现重复的时候。

C此时想到,引入一个二维数组,将访问过的点存储起来,以便减少访问次数(递归时直接读取数据)。

自然而然引出来记忆化暴力搜索:

  程序:

int Max_serch(int x,int y){
    memset(Temp,0,sizeof(Temp));
    if(Temp[x][y]!=0){
    	return Temp[x][y];
	}
	if(x==n-1||y==n-1){
    	return Data[x][y];
	}else{
		Temp[x][y]=max(Max_serch(x+1,y),Max_serch(x+1,y+1))+Data[x][y];
	}
	return Temp[x][y];
}

进一步考虑有没有更好的方法:将临时存储数据的Temp[x][y]数组:存储的是第x行,第y列最优的解,那么最底一行存的一定是Data[x][y]的数据,那么问题就变成了由下到上逐步求解了。

(1).#include<bits/stdc++.h>
using namespace std;
int Data[101][101];	
int Temp[101][101];
int n;
int Max_serch(){
    memset(Temp,0,sizeof(Temp));
    if(n==1)
     return Data[0][0];
    for(int i=n-1,j=0;j<n;j++){
    	Temp[i][j]=Data[i][j];
    	//cout<<Temp[i][j]<<" ";
	}
	for(int k=n-2;k>=0;k--){
		for(int j=k;j>=0;j--){
			Temp[k][j]=max(Temp[k+1][j],Temp[k+1][j+1])+Data[k][j];
		}
	}
	return Temp[0][0];
}
int main()
{
   cin>>n;
   for(int i=0;i<n;i++){
   	for(int j=0;j<=i;j++){
   		cin>>Data[i][j];
	   }
   }
   int sum;
   sum=Max_serch();
   cout<<sum<<endl;
return 0;
}


 

在最后进行分析不难发现还可以进一步优化(空间优化),那就是将临时变量Temp都不需要只需要一行数组就行,用原始的Data数据中最右列存储。


int Max_serch(){
    if(n==1)
     return Data[0][0];
    for(int i=0;i<n;i++){
    	Data[i][n-1]=Data[n-1][i];
    //	cout<<Data[i][n-1]<<" ";
	}
	for(int k=n-2;k>=0;k--){
		for(int j=0;j<=k;j++){
			Data[j][n-1]=max(Data[j][n-1],Data[j+1][n-1])+Data[k][j];
		}
	}
	return Data[0][n-1];
}


程序:

此外学习动态规划的典型应用也是很有必要的,对于常见的类型我们要直接记住动态规划的方法(最优二叉搜索树,最长公共子序列,钢条切割)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值