题目如下:
题目详情 - 湮灭残昼 - 南阳理工学院OJ (nyist.edu.cn)
题目大意为:输入m和n 解出n个非负数的整数的和为m的解的个数 (注意是非负数 含零 比赛时就没认真读好题以为不含零)其中只要有一个数不同则作为不同解 比如m=2 n=2 那么 0 2 和2 0被认为是两组解
在看到题目的那一刻,我也是懵逼的,无思路,但该题明显就是个数学问题,可以试着找找规律看看,那么就从打表开始吧:我们可以先打几组解看看能不能看出点东西
小数据甚至可以通过多个for循环找出来(其实赛时我也想过直接打表然后printf 但最后发现数太大最后放弃
m\n | 1 | 2 | 3 | 4 | 5 | 6 |
1 | 1 | 2 | 3 | 4 | 5 | 6 |
2 | 1 | 3 | 6 | 10 | 15 | 21 |
3 | 1 | 4 | 10 | 20 | 35 | 56 |
4 | 1 | 5 | 15 | 35 | 70 | 126 |
5 | 1 | 6 | 21 | 56 | 126 | 252 |
6 | 1 | 7 | 28 | 84 | 210 | 462 |
虽然题目数据给的为n<=m 但我们可以扩大范围找规律
在打了个6*6的表后,我们不难发现(学过动态规划)好像确实有点规律?比如m=4和n=4的答案是m=4 n=3和m=3 n=4的和 即jay[4][4]=jay[4][3]+jay[3][4]再多看几组发现好像都可以满足这个式子dp[m][n]=dp[m-1][n]+dp[m][n-1]那么答案就可以的出来了
但又有人说了 没学过dp或者根本没看出来时dp怎么办 那么就可以用排列组合解决此问题,因为我们通过观察每个答案,好像不无规律?
比如当m=1时不管n=?即答案都为n
n=1 m=?时答案都为1
此时我们好像发现了 好像与高中学过的排列组合相同?
也就是这个东西
我们发现当n=1时Cm n均为m
当n=0时Cm n均为1
好像与上面照应住了
那我们通过表上对应的每个数 得出一个结论 答案为
此时我们好像发现,与高中数学中学的排列组合里面的隔板法有点像
那么就会有人要说了 要是在高中(智力巅峰,我分分钟解决这个问题
但现在我是大学生 (干饭巅峰
那么我们来重新回忆一下隔板法
直接上例题ba:
有10个相同的球,要放进3个不同盒子里,并允许空盒子 求总的方案数(隔板法
乍一看好像没什么思路?因为是允许有空盒子存在
那换一道例题再看看:
有7个相同的球 放进三个不同的盒子里 每个盒子至少有一个球(插空法
隔板法不熟悉,那这个我们还不熟悉?高中成天用的插空法
7个球,有8个空,因为不可空,所以两端不能再选,于是就相当于剩下6个空 那么只需要插2个空就可以分成三份
那么答案就是C6 2 =15
所以插空法的模板就是 m个球 放进n个不同盒子 盒子至少有一个球
答案为:
那么我们可以回到最上面的题
有10个相同的球,要放进3个不同盒子里,并允许空盒子 求总的方案数
因为该题是允许有空盒子存在,所以不能直接用公式 那么我们可以换个思路看看
把每个盒子都加一
那么就变成了有13个相同的球,要放进3个不同盒子里,每个盒子至少一个球 求总的方案数
那么答案就很显然 直接就为Cm-1 n-1了
此时我们推出来了隔板法
我们可以将隔板法总结为 求n个数(非负数)的和为m的总方案数
那么我们就发现和题目的意思一模一样
所以该题就是隔板法 只不过是用代码实现而已
公式确实是这样 但我们如果硬求某个数的阶乘 可能会爆(数太大
所以我们要优化 要乘着化简着
例如C9 3=9*8*7/3*2*1=9/1*8/2*7/3
隔板法AC代码如下
我们要注意 此时为什么不开int类型
我们可以举一组例子,比如C9 3=9/1*8/2*7/3
如果用int类型 那么7/3则会默认向下取整为2
但实际并不为2 所以如果用int 可能会直接的wrong answer
所以我们要用double类型 来确保每次相乘不会使答案发生改变
dpAC代码如下:
注意m=1和n=1时要把数组初始化完毕
谢谢观看,有什么不足之处多多指教