竞赛题目讲解-【Standard IO】数的划分
2017-07-06 12:04
218 查看
【Standard IO】数的划分
(注册登录后详见:NOI在线题库:数的划分问题1)题目描述
把正整数N分解成M个正整数的和,即使M个数相同但顺序不同也认为是不同的方案,要求总方案数。如3=1+2跟3=2+1是两个不同的方案。
输入
第一行包含两个整数N和M(1<=M<=N<=50)。
输出
输出一个数表示方案数。
样例输入
3 2
样例输出
2
数据范围限制
1<=M<=N<=50
题目解析
一、部分一——从深度优先搜索到记忆化搜索
如果只看这道题的描述,我们可能认为是一道深度优先搜索题,但是再看数据范围(虽然数据小但运算量惊人的大),明显用深度优先搜索会超时,那么广度优先搜索如何?然而数据之间并没有很强的连续性,所以广度优先搜索难以写出代码。那要如何写,这就要涉及到搜索的优化——记忆化搜索。记忆化搜索其实是深度优先搜索的一种,所以我们能够发现它的外部框架完全是深度优先搜索。它适用于许多数据中等的题,我们可以用数组(一维,二维甚至是三维,四维)来储存一些用公式连接起来的数据,其维数通常是涉及到的数据数量,每一维分别表示一个数据。
那么这道题用记忆化搜索怎么写呢?我们可以把深度优先搜索搜索改一下(深度优先搜索的源代码见文章尾部的程序样例),即“添加记忆”,一般来说是设置一些边界,通过这些边界求出各个元素的值,储存在容器(多为数组)中,若下次再次访问到这个元素,就直接调用容器中已有的值就行了。我们可以简单分析一下边界——
1. 因为是要拆分为正整数,所以被拆分数首先要是个正整数,也就是被拆分数≥1。所以第一个边界是当被拆分数<1时,返回0。
2. 若只要求拆分出1个数,则必定是被拆分数本身。则第二个边界是当要求拆分的数量为1时,返回1。
3. 如果被拆分数和要求拆分出的数相等,则只能全部拆为1。则第三个边界为当被拆分数和要求拆分的数量相等,返回1。
然后因为是记忆化搜索,我们就用一个二维数组(F)作为容器。简单分析可以得出F[i][j]等于它所有分支的和。得出递归式-
F[i][j]=F[i-1][j-1]+F[i-2][j-1]+...+F[1][j-1]。
将递归式代入递归,然后储存入F数组里,调用并输出。
二、部分二——从记忆化搜索到动态规划
其实这道题在OJ里是分在动态规划的,也就是说它实际上是用动态规划来解题的。学过动态规划的同学可能知道,记忆化搜索其实也是动态规划的一种,它的形式类似于递归(有时候它也可以写成记忆化递归)。而众所周知,只要能用递归做的题递推也能做,从记忆化搜索到动态规划其实就是从递归到递推。
首先我们要将记忆化搜索中的边界以预处理的形式表现出来,然后我们分析一下记忆化搜索的作用——从一处倒退,分步求出每一个位置的值,最终得出答案。也就是说记忆化搜索是把所有位置的值求出来的方式,若要递推,我们可以从矩阵(数组)的左上角开始遍历(Tab:从左上角开始的原因一是方便,二是与已知边界值更加接近),根据预处理的边界依次推出各个元素的值,注意若该元素已经计算过(预处理过),则不要再次计算。
三、部分三——优化处理
说了这么多,我们最后也只输出一个答案,为何不把矩阵中所有元素的值都输出来呢(左上角开始编号)?
1|1 2|1 1 3|1 2 1 4|1 3 3 1 5|1 4 6 4 1 6|1 5 10 10 5 1 .|. . . . . . . .|. . . . . . . .|—————————————————— n 1 2 3 4 5 6 . . .
我们乍一看没有什么规律,但是变成这样…
!?这不是杨辉三角形吗?
你也许会说:只是巧合。但实际上并不是,若我们设F(i,j)表示第i层第j个数的值,则我们知道 F(n,1)|n>0 为1是边界值,则我们知道:
F(i,j)=F(i-1,j-1)+F(i-2,j-1)+...+F(1,j-1)|j-1>0
例如F(6,4)=10,我们会发现:
F(6,4)=F(5,3)+F(4,3)+F(3,3) =F(4,2)+F(3,2)+F(2,2)+F(3,2)+F(2,2)+F(2,2) =F(3,1)+F(2,1)+F(1,1)+F(2,1)+F(1,1)+F(1,1)+F(2,1)+F(1,1)+F(1,1)+F(1,1) =F(3,1)+3*F(2,1)+6*F(1,1) =1+3+6 =10
即杨辉三角形的另一种求法。因此,我们可以预处理出一个杨辉三角形,然后输出-输入所对应的值(F[m]
)。
这个样例程序就不给出了,大家多加思考写出来提交一下吧(网站在最上面)。
题外话
作者其实也是刚学动态规划,感觉编程的世界多么奇妙。原来40多行的搜索,动态规划几个for循环就搞定了,但是作者确实对动态规划不熟,如果文章中有解释不清的请大家谅解。
又及,我们老师叫我们写一个深度优先搜索的代码,叫我们必须弄出一个TLE(时间超限)来,可怜我的正确率啊…
程序样例
一、明知道要超时还偏要提交的深度优先搜索
#include<cstdio> int n,m,ans; void flag(int num,int need) { if(need==0 && num==0) { ans++; return; } if(need==0 || num==0) return; for(int i=1;i<=num;i++) flag(num-i,need-1); } int main() { scanf("%d%d",&n,&m); flag(n,m); printf("%d\n",ans); return 0; }
二、把正确率赚回来了的记忆化搜索
/* Lucky_Glass */ #include<cstdio> int n,m;long long F[55][55]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(j==1 || i==j) F[i][j]=1; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(i>=j) { int t=i-j+1; if(F[i][j]) continue; for(int k=1;k<=t;k++) F[i][j]+=i-k>=1? F[i-k][j-1]:0; } printf("%lld\n",F [m]); return 0; }
三、3个不同版本的动态规划——团队合作的杰作
1.
/* Lucky_Glass */ #include<cstdio> int n,m;long long F[55][55]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=50;i++) F[i][i]=F[i][1]=1; for(int j=1;j<=m;j++) for(int i=1;i<=n;i++) if(!F[i][j]) for(int k=1;k<i;k++) F[i][j]+=F[i-k][j-1]; printf("%lld\n",F [m]); return 0; }
2.
/* Lucky_Glass */ #include<cstdio> int n,m;long long F[55][55]; int main() { scanf("%d%d",&n,&m); F[0][0]=1; for(int j=1;j<=m;j++) for(int i=1;i<=n;i++) for(int k=1;k<=i;k++) F[i][j]+=F[i-k][j-1]; printf("%lld\n",F [m]); return 0; }
3.
/* Lucky_Glass */ #include<cstdio> int n,m;long long F[55][55]; int main() { scanf("%d%d",&n,&m); for(int i=1;i<=50;i++) F[i][i]=F[i][1]=1; F[0][0]=1; for(int j=1;j<=m;j++) for(int i=1;i<=n;i++) if(!F[i][j]) for(int k=1;k<i;k++) F[i][j]+=F[i-k][j-1]; printf("%lld\n",F [m]); return 0; }
相关文章推荐
- 竞赛题目讲解-【Standard IO】产生数
- 竞赛题目讲解-【Central Europe 1996】装箱问题
- 竞赛题目讲解-【Rocky Mountain 2004】最短前缀
- 竞赛题目讲解-【Greater New York 2001】最大子矩阵
- 竞赛题目讲解 - 【USACO TRAINING】子集的和
- 竞赛题目讲解-【Northeastern Europe 2002, Far-Eastern Subregion】最长上升子序列
- 竞赛题目讲解-【Japan 2002 Kanazawa】碎纸机
- 竞赛题目讲解-【NOIP2000提高组】乘积最大
- 竞赛题目讲解-【NOIP2000复赛 普及组】单词接龙
- 2014高教社杯全国大学生数学建模竞赛题目 B题 创意平板折叠桌
- 计算几何题目入门-8月6号讲解
- 关于一些初级ACM竞赛题目的分析和题解(二)。
- 【Android进阶】Android面试题目整理与讲解
- 2017年上海金马五校程序设计竞赛(网上资格赛)部分题目题解
- cuda线程的划分详细讲解threadIdx.x
- ◆竞赛题目◆◇NOIP2015普及组◇求和
- 数据挖掘竞赛题目 -- 文本分类
- 子网规划与划分实例讲解
- 竞赛排名 (Standard IO)
- [hihoCoder太阁最新面经算法竞赛9] 题目一:Browser Caching (LRU缓存)