博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
两道题学习动态规划
阅读量:6710 次
发布时间:2019-06-25

本文共 2415 字,大约阅读时间需要 8 分钟。

动态规划,是为了解决overlap sub-problem(重叠子问题)。最重要的是状态的定义和状态转移方程的定义,而把状态转移方程确定,一般是最难的一步。

学习动态规划,可以先把递归过程理解清楚,再使用非递归的方法,来求解问题,来避免重复计算。

参考:

下面是两道例题:


  • 在一个数组arr中,找出一组不相邻的数字,使得最后的和最大。

input

arr=1 2 4 1 7 8 3

output

15

opt[i]表示下标为i的最佳方案, + - 表示选与不选该数,例如opt[6],选了下标为6的数,那么opt[6] = opt[4] + arr[6],如果不选,那么opt[6] = opt[5];接下来就是求两个的最大值,得到最佳。下面的图显示了他们的递推关系,也出现了重叠子问题。

1227382-20190122211034888-1929138389.png
接着就可以找到递推方程,也就是状态转移方程
1227382-20190122212118640-1971669214.png

一旦我们确定出这个方程,就可以很快的用递归来实现

int rec_opt(int a[],int i){    if( i == 0 )    {        return a[0];    }else if(i == 1)    {        return max(a[0],a[1]);    }else    {        int t1 = rec_opt(a,i-2) + a[i];        int t2 = rec_opt(a,i-1);        return max(t1,t2);    }}

接下来就是解决重叠子问题,使用非递归来实现

int dp_opt(int a[]){    opt[0] = a[0];    opt[1] = max(a[0],a[1]);    for(int i = 2; i < N; i++)    {        int t1 = opt[i-2]+a[i];        int t2 = opt[i-1];        opt[i] = max(t1,t2);    }    return 0;//这里我直接返回了0,实际上最后的最佳方案就是opt[6],因为测试数据包含7个数据。}

  • 给定一个正整数s, 判断一个数组arr中,是否有一组数字加起来等于s。

input

arr=3 34 4 12 5 3
s=9
s=13

output

True
False

1227382-20190122214152228-906279098.png

接下里就是比较难找的递归出口情况

前两种情况很快就能得出,第三种情况不容易想到
1227382-20190122214654676-1523961820.png
有了上图的状态方程,就可以写出递归了

bool rec_subset(int a[], int i, int s){    if(s == 0)//递归的三个出口        return true;    else if (i == 0)        return a[0] == s;    else if(a[i] > s)        return rec_subset(a,i-1,s);    else{        int t1 = rec_subset(a,i-1,s - a[i]); //选        int t2 = rec_subset(a,i-1,s);//不选        if(t1 || t2)            return true;    }}

接下来就是比较麻烦的非递归实现

这里设置一个二维数组来实现

1227382-20190122215916654-258727637.png

下面是代码实现

bool dp_subset(int a[],int n,int s){    int **subset;    int i,j;    subset = (int **)malloc(sizeof(int *)*n);    for (i=0; i < n; i++)        subset[i] = (int *)malloc(sizeof(int)*(s+1));        for(i = 0; i <= s; i++)    {        subset[0][i] = 0; //将第0行设置为false    }    for(i = 0; i < n; i++)        subset[i][0] = 1;//将第0列设置为false    if(a[0] <= s)    {        subset[0][a[0]] = 1;//s == arr[0],subset[0][a[0] = 1;这里需要判断,否则可能会发生越界    }    for(i = 1; i < n; i++)    {        for(j = 1; j <= s; j++)        {            if(a[i] > j)                subset[i][j] = subset[i-1][j]; //递归第三个出口判断            else            {                //接下来就是递推式中的两种情况 or                int t1 = subset[i-1][j-a[i]];                int t2 = subset[i-1][j];                subset[i][j] = t1 || t2;            }        }    }    int temp = subset[n-1][s];    for(i = 0; i < n;i++)        free(subset[i]);    free(subset);    return temp;}

所以,动态规划 = 用数组记录中间过程的递归?

转载于:https://www.cnblogs.com/hish/p/10305980.html

你可能感兴趣的文章
最老程序员创业札记:全文检索、数据挖掘、推荐引擎应用15
查看>>
学生信息管理系统总结
查看>>
AJAX GET和POST传递参数
查看>>
Ubuntu 16.04 Java8环境安装【转载】
查看>>
远程监控基础知识和故障排除
查看>>
Android IntentService全然解析 当Service遇到Handler
查看>>
C/C++获取本地时间常见方法
查看>>
C#/JavaScript/SqlServer 对日期时间的操作整理汇总
查看>>
抢购页面JS
查看>>
实战:配置DNS客户端域名搜索后缀构造域名进行域名解析
查看>>
公开课视频-《第03章 部署-IT基础架构》-大企业云桌面部署实战-在线培训-视频(奉献)...
查看>>
数据库ORA-03113排查
查看>>
读书笔记-看见未来:改变互联网世界的人们
查看>>
Symfony2CookBook:如何创建自定义的表单域类型
查看>>
HCP Anywhere:为HDS内容云锦上添花
查看>>
分享B2B信息发布小技巧
查看>>
你不得不知道的Visual Studio 2012(3)- 创建Windows应用程序
查看>>
Linux环境下C语言模拟内存负载测试
查看>>
Cocos Creator中的动画支持技术
查看>>
“2012年度IT博客大赛”获奖感言--梦想、学习、坚持、自信、淡定
查看>>