动态规划问题(一)

在学习过程中,遇到动态规划问题。查了很多的资料,终于会一点点了。

动态规划一般思路:

1  将原问题转化成子问题求解。

蒋原问题转换成若干个子问题,子问题和原问题相同或相似,但是规模会小,子问题解决,原问题便解决。

子问题求出后便保存,只求一次。子问题解决,原问题即解决。

2 确定状态

这一段是copy来的;

  • 在用动态规划解题时,我们往往将和子问题相关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。
  •     所有“状态”的集合,构成问题的“状态空间”。“状态空间”的大小,与用动态规划解决问题的时间复杂度直接相关。

我的理解就是状态就是表示每个子问题的值得集合。用来表示和确定每个子问题。

3 确定初始状态和边界状态。

4 确定状态转移方程。(重点与难点)

从一个状态推出下一个状态的递推方程,便是状态转移方程。这个靠经验还有猜。

例题:

数字三角形(POJ1163)

    

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

    输入格式:

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

    7

    3   8

    8   1   0

    2   7   4   4

    4   5   2   6   5

    要求输出最大和:

可以用简单的递归来写这个程序:

#include <iostream>    
#include <algorithm>   
using namespace std;  
int D[101][101];      
int n;    
int max101][101];  
int Max(int i, int j){        
    if( max[i][j] != -1 )   {
        return max[i][j];
    }
    if(i==n){     
        max[i][j] = D[i][j];
    }
    else{      
        int x = Max(i+1,j);         
        int y = Max(i+1,j+1);         
        max[i][j] = max(x,y)+ D[i][j];       
    }       
    return max[i][j];   
}   
int main(){      
    int i,j;      
    cin >> n;      
    for(i=1;i<=n;i++){     
        for(j=1;j<=i;j++) {         
            cin >> D[i][j];         
            max[i][j] = -1;     
        }      
    }
    cout << Max(1,1) << endl;   
}   

但是这样做会超时,因为重复计算太多了。但是我们可以把每一次,max都记录下来,这样就可以节省大量的时间。

#include <iostream>    
#include <algorithm>      
using namespace std;   
int D[101][101];    
int n;    
int Max(int i, int j){      
    if(i==n){    
        return D[i][j];
    }
    else {
    int x = Max(i+1,j);      
    int y = Max(i+1,j+1);      
    return max(x,y)+D[i][j];
    }
}  
int main(){      
    int i,j;      
    cin >> n;      
    for(i=1;i<=n;i++){     
        for(j=1;j<=i;j++){          
            cin >> D[i][j];
        }
    }
    cout << Max(1,1) << endl;    
}        

也可以用动态规划的方法来写:

动态转移方程:

 max[i][j] = max(max[i+1][j],max[i+1][j+1]) + D[i][j];

i--;j++;

代码:

#include <iostream>    
#include <algorithm>   
using namespace std;   
int D[101][101];     
int n;    
int max[101][101];   
int main(){      
    int i,j;      
    cin >> n;      
    for(i=1;i<=n;i++)  {   
        for(j=1;j<=i;j++){          
            cin >> D[i][j];
        }
    }
    for( int i = 1;i <= n; ++ i )   {    
        max[n][i] = D[n][i];     
    }
    for( int i = n-1; i>= 1;  --i ){       
        for( int j = 1; j <= i; ++j ){           
            max[i][j] = max(max[i+1][j],max[i+1][j+1]) + D[i][j];
        }
    }
    cout << max[1][1] << endl;    
}   





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值