北京大学暑期课《ACM/ICPC竞赛训练》 ppt摘取

什么是动态规划?

●递归到动规的一般转化方法 

递归函数有n个参数,就定义一个n维的数组,数组 的下标是递归函数参数的取值范围,数组元素的值 是递归函数的返回值,这样就可以从边界值开始, 逐步填充数组,相当于计算递归函数值的逆过程。

动规解题的一般思路 

1. 将原问题分解为子问题 

把原问题分解为若干个子问题,子问题和原问题形式相同 或类似,只不过规模变小了。子问题都解决,原问题即解 决(数字三角形例)。 

子问题的解一旦求出就会被保存,所以每个子问题只需求 解一次。 

2. 确定状态 

在用动态规划解题时,我们往往将和子问题相 关的各个变量的一组取值,称之为一个“状 态”。一个“状态”对应于一个或多个子问题, 所谓某个“状态”下的“值”,就是这个“状 态”所对应的子问题的解。 

 所有“状态”的集合,构成问题的“状态空间”。“状态 空间”的大小,与用动态规划解决问题的时间复杂度直接相关。 在数字三角形的例子里,一共有N×(N+1)/2个数字,所以这个 问题的状态空间里一共就有N×(N+1)/2个状态。         

整个问题的时间复杂度是状态数目乘以计算每个状态所需 时间。             

在数字三角形里每个“状态”只需要经过一次,且在每个 状态上作计算所花的时间都是和N无关的常数。

用动态规划解题,经常碰到的情况是,K个整型变量能 构成一个状态(如数字三角形中的行号和列号这两个变量 构成“状态”)。如果这K个整型变量的取值范围分别是 N1, N2, ……Nk,那么,我们就可以用一个K维的数组 array[N1] [N2]……[Nk]来存储各个状态的“值”。这个 “值”未必就是一个整数或浮点数,可能是需要一个结构 才能表示的,那么array就可以是一个结构数组。一个 “状态”下的“值”通常会是一个或多个子问题的解。 

3. 确定一些初始状态(边界状态)的值  
       以“数字三角形”为例,初始状态就是底边数字,值 就是底边数字值。 

4. 确定状态转移方程  
       定义出什么是“状态”,以及在该 “状态”下的“值”后,就要 找出不同的状态之间如何迁移――即如何从一个或多个“值”已知的 “状态”,求出另一个“状态”的“值”(“人人为我”递推型)。状 态的迁移可以用递推公式表示,此递推公式也可被称作“状态转移方 程”。       

能用动规解决的问题的特点 

1) 问题具有最优子结构性质。如果问题的最优解所包含的 子问题的解也是最优的,我们就称该问题具有最优子结 构性质。

 2) 无后效性。当前的若干个状态值一旦确定,则此后过程 的演变就只和这若干个状态的值有关,和之前是采取哪 种手段或经过哪条路径演变到当前的这若干个状态,没 有关系。 

动归的三种形式 

1)记忆递归型    

优点:只经过有用的状态,没有浪费。递推型会查看一些 没用的状态,有浪费    

缺点:可能会因递归层数太深导致爆栈,函数调用带来额 外时间开销。无法使用滚动数组节省空间。总体来说,比递推 型慢。

2) “我为人人”递推型     

没有什么明显的优势,有时比较符合思考的习惯。个别特 殊题目中会比“人人为我”型节省空间。

状态i的值Fi在被更新(不一定是 最终求出)的时候,依据Fi去更 新(不一定是最终求出)和状态i 相关的其他一些状态的值 Fk,Fm,..Fy 

                      Fk 
                      Fm 
   Fi    ->        Fx 
                      Fy 
                      …    

3)“人人为我”递推型动归  

状态i的值Fi由若干个值 已知的状态值Fk,Fm,..Fy 推出,如求和,取最大值 …… 

在选取最优备选状态的值Fm,Fn,…Fy时, 有可能有好的算法或数据结构可以用来显 著降低时间复杂度。 

Fk 
Fm 
Fx      ->     Fi 
Fy 
… 


例题 神奇的口袋(百练2755)

有一个神奇的口袋,总的容积是40,用这个口袋可以变出一 些物品,这些物品的总体积必须是40。

John现在有n(1≤n ≤ 20)个想要得到的物品,每个物品 的体积分别是a1,a2……an。John可以从这些物品中选择一 些,如果选出的物体的总体积是40,那么利用这个神奇的口 袋,John就可以得到这些物品。现在的问题是,John有多少 种不同的选择物品的方式。

输入

输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的 数目。接下来的n行,每行有一个1到40之间的正整数,分别 给出a1,a2……an的值。

输出

输出不同的选择物品的方式的数目。

输入样例 3 20 20 20

输出样例 3


1.枚举的解法:

枚举每个物品是选还是不选,共2^20种情况

2.递归解法

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define N 100
int a[N],n;
int ways(int n,int w)   //从前n种物品中选择一些,凑成体积w的做法数目
{if(w==0) return 1;if(n<=0) return 0;return ways(n-1,w)+ways(n-1,w-a[n]);
}
int main()
{cin>>n;for(int i=1;i<=n;i++)cin>>a[i];cout<<ways(n,40)<<endl;return 0;
}

动规解法

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define N 100
int dp[N][50],n,a[N];  //dp[i][j]表示从前i种物品里凑出体积j的方法数 int main()
{cin>>n;for(int i=1;i<=n;i++){cin>>a[i];dp[i][0]=1;}dp[0][0]=1;for(int i=1;i<=n;i++){for(int j=1;j<=40;j++){dp[i][j]=dp[i-1][j];if(j>=a[i])dp[i][j]+=dp[i-1][j-a[i]];}}cout<<dp[n][40]<<endl;return 0;
}


“我为人人”型递推解法

此问题仅在询问容积40是否可达,40是个很小的 数,可以考虑对值域空间-即对容积的可达性进行动态 规划。
定义一维数组 int sum[41];依次放入物品,计算每次放入物品可达的容积, 并在相应空间设置记录,最后判断sum[40] 是否可达 ,到达了几次。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define N 100
int dp[N],n,a;int main()
{cin>>n;memset(dp,0,sizeof(dp));for(int i=1;i<=n;i++){cin>>a;for(int j=40;j>=1;j--)   //一定为逆序,否则会重复更新if(dp[j]>0&&j+a<=40)dp[j+a]+=dp[j];//如果j有dp[j]种方式可达,则每种方式加上a就可达 j+adp[a]++;}cout<<dp[40]<<endl;return 0;
}


最长上升子序列的“我为人人”做法:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define N 1000
int dp[N],n,a[N];int main()
{cin>>n;for(int i=1;i<=n;i++){cin>>a[i];dp[i]=1;}for(int i=1;i<=n;i++){for(int j=i+1;j<=n;++j) //看看能更新哪些状态的值{if(a[j]>a[i])dp[j]=max(dp[j],dp[i]+1);}}cout<<*max_element(dp+1,dp+n+1)<<endl;return 0;
}




北大培训课动态规划----神奇的口袋(百练2755)相关推荐

  1. 【算法练习】动态规划/搜索/状态压缩 百练poj4124:海贼王之伟大航路

    参考链接:https://www.twblogs.net/a/5b8ceaac2b7177188336e93d/zh-cn 题目链接:http://bailian.openjudge.cn/pract ...

  2. 动态规划之神奇的口袋问题

    问题描述 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40 John现在有n(1<=n<=20)个想要得到的物品,每个物品的体积分别是a1,a2,- ...

  3. 动态规划之神奇的口袋

    动态规划之神奇的口袋 题目 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40. John现在有n(1≤n ≤ 20)个想要得到的物品,每个物品的体积分别是a1, ...

  4. 神奇的口袋(动态规划)--算法学习

    问题描述 有一个神奇的口袋,总的容积是40,用这个口袋可以变出 一些物品,这些物品的总体积必须是40.  John现在有n(1≤n ≤ 20)个想要得到的物品,每个物品 的体积分别是a1,a2--a ...

  5. 神奇的口袋 C++ 三种方法(枚举,递归,动态规划)

    2755:神奇的口袋 查看 提交 统计 提示 提问 总时间限制: 10000ms 内存限制: 65536kB 描述 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是 ...

  6. 香帅的北大金融学课笔记16 -- 公司决策

    香帅的北大金融学课笔记 – 公司决策 一.财务报表 1.财务报表基础:三张表 1)资产负债表 资产:个人资产有房产.股票.债券.理财产品.黄金.现金.投资项目等.正确的排列顺序是按照资产的流动性来排. ...

  7. IT培训课、视频教程和书本之PK

    有不少Java初学者问我:"我想学Java,到底该报个培训班呢,还是到网上下载一些视频看看呢,还是自己找本书看呢?" 培训课.视频教程和书本都可以帮助你学习某种技术.本人碰巧不仅是 ...

  8. 一堂如何提高代码质量的培训课【转】

    今天这堂培训课讲什么呢?我既不讲Spring,也不讲Hibernate,更不讲Ext,我不讲任何一个具体的技术.我们抛开任何具体的技术,来谈谈如何提高代码质量.如何提高代码质量,相信不仅是在座所有人苦 ...

  9. 此文胜过你听三年的培训课

    [转] 此文胜过你听三年的培训课,最少省十万!  你做老板,你做生意,你开店,你做夜场,你开工厂,你做服务业,等等,不管你做那一行,看完这篇文章,理解透了,就等于你清华大学MBA毕业了.文章很长慢慢读 ...

最新文章

  1. LFFD ncnn torch
  2. python之父叫什么-Python之父谈Python的未来形式
  3. Pat乙级 1058 选择题
  4. python——xpath
  5. 并归排序(看别人的看不懂,自己写了一个),排序思想是一样的
  6. .netcore2.0 发布CentOS7
  7. ES6系列之Set Map
  8. 使用display inline-block 布局时,出现的间距问题的解决办法和相关说明
  9. offsetTop、offsetLeft、offsetWidth、offsetHeight、style中的样式
  10. (三)python3 只需3小时带你轻松入门—— 变量的简单运算
  11. OpenCV-获取图像中直线上的数据
  12. 小程序发布,你方了么?
  13. 适用于商业的10款最佳Android应用模板
  14. SOA架构中企业数据总线(ESB)和微服务架构中注册服务管理(dubbo)的区别
  15. PLC是什么?它的作用是什么?
  16. 利用cobbler 重装系统
  17. 开源OSSIM企业运维疑难问题解析
  18. 力扣算法——78_子集
  19. (二十七)论文阅读 | 目标检测之MAL
  20. 二维动态数组空间分配 c语言,科学网—C语言中动态二维数组的使用和分配 - 王一哲的博文...

热门文章

  1. js分割thymleaf的字符串
  2. 能力不够,你就态度好点
  3. 【汽车配件管理系统-管理员-配件管理模块】配件管理分类
  4. marvelous designer 10安装使用教程(附快捷键)
  5. 一些png图片单独打开是透明的,怎么在ps里打开来就变不透明了
  6. Spring定时任务多线程
  7. 【全年汇总】2023年CCF计算机图形学与多媒体会议截稿时间汇总(持续更新)
  8. 利用笔记本电脑给只能访问内网linux服务器共享网络,使其也能访问外网
  9. 吉林大学计算机孙磊,室内灯光控制系统设计毕业论文.doc
  10. WebLogic之WebLogic安装