《算法竞赛入门经典》计算组合数问题
计算组合数
编写函数,参数是两个非负整数n和m,返回组合数
其中m<=n<=25。例如,n=25,m=12时的答案为5200300。
代码及算法分析
程序4-1 组合数(有问题)
#include <stdio.h>
long long factorial(int n)
{long long m=1;//不要忘记初始化,不然的出来的结果惊人。for(int i=1;i<=n;i++){m*=i;}return m;
}
int main ()
{int n,m;scanf("%d %d",&n,&m);printf("%lld",factorial(n)/(factorial(m)*factorial(n-m)));return 0;
}
这个代码的问题显而易见,阶乘容易溢出,所以不可取。
所以,套用刘汝佳老师的一句话:”即使最终答案在所选择的数据类型范围之内,计算的中间结果仍然可能溢出“。
汝佳老师也给出了相应的解决方案,虽然不能完全避免中间结果溢出,但是对于题目给出的范围已经可以保证得到正确的结果了。
先来分析一下组合数的公式:
n!
————
m!(n-m)!
展开之后:
n *(n-1) *(n-2)……3 *2 *1
—————————————————————————————(1)
m *(m-1) *(m-2)……3 *2 *1 *(n-m) *(n-m-1) *(n-m-2)…… *3 *2 *1
因为n>=m,所以m在1~n之间,这样可以把n!除以m!约分:
n *(n-1) *(n-2)……(m+2) *(m+1)
————————————————(2)
(n-m) *(n-m-1) *(n-m-2)…… *3 *2 *1
然后汝佳老师给了一道思考题:为什么当m<n-m时要把m变成n-m?
移项之后得到:m<n/2,先列一个数轴:
|————————————————————>
0 1 2 3 ……m……n/2……M……(n-1) n
为了不把变换后的m与变换前的m弄混,把变化后的m记为M。因为组合数的公式,分子是大于分母的,所以分子的乘积比较大,容易溢出,要想优化,就得让分子乘积变小。
M=n-m带入组合式公式之后就是:
n!
————————————————(3)
M!(n-M)!=(n-m)!(n-(n-m))!=(n-m)!m!
所以式子并没有变化,同样可以进行约分得到(2)式的变式:
n *(n-1) *(n-2)……(M+2) *(M+1)
————————————————(4)
(n-M) *(n-M-1) *(n-M-2)…… *3 *2 *1
相当于将数轴
|————————————————————>
0 1 2 3 ……m ……n/2……M ……(n-1) n
标出的部分直接干掉了。
由于M是大于m的,所以分子的乘积缩小,溢出问题得到缓解,注意,是缓解不是解决,如果n和m的值很大的话还是会溢出。
分析之后就可以把程序4-1升级为程序4-2了:
#include <stdio.h>
long long c(int n,int m)
{if(m<n-m){m=n-m;}long long ans=1;for(int i=m+1;i<=n;i++){ans*=i;}for(int i=1;i<=n-m;i++){ans/=i;}return ans;
}
int main ()
{int n,m;scanf("%d %d",&n,&m);printf("%lld",c(n,m));return 0;
}
汝佳老师提示
“对复杂的表达式进行化简有时不仅能减少计算量,还能减少甚至避免中间结果的溢出。”
《算法竞赛入门经典》计算组合数问题相关推荐
- 刘汝佳《算法竞赛入门经典》---总结
刘汝佳:<算法竞赛入门经典> 三步: 基本的数据结构+算法知识: 数论等数学基本知识: 锻炼联想建模能力.知识与实际相结合,解决实际问题! 第一章:程序设计入门 1.a/b 当a.b为整数 ...
- 算法竞赛入门经典(刘汝佳)——代码笔记
Reference: <算法竞赛入门经典>(刘汝佳)第一版.第二版 ------------------------------------------------------------ ...
- 《算法竞赛入门经典训练指南》pdf
下载地址:网盘下载 基本介绍 编辑 内容简介 <算法竞赛入门经典:训练指南>题目多选自近年来ACM/ICPC区域赛和总决赛真题,内容全面,信息量大,覆盖了常见算法竞赛中的大多数细分知识点. ...
- 算法竞赛入门经典训练指南
最近在看算法竞赛入门经典训练指南这本书,书中不错的算法我将在博客中发布,和大家共同学习. 题目: 在你的王国里有一条n个头的恶龙,你希望雇一些骑士把它杀死(即砍掉所有头).村里有m个骑士可以雇佣,一个 ...
- 算法竞赛入门经典 习题3-2 分子量 Molar Mass
给出一种物质的分子式(不带括号),求其分子量.本题分子式中只包含四种原子,分别为C.H.O.N,原子量分别为12.01,1.008,16.00,14.01.例如,C6H5OH的分子量为94.108g/ ...
- 算法竞赛入门经典(第二版)第三章习题
声明:作者水平有限,只是会基础C语言的小菜,C++还未入门.作者仅根据算法竞赛入门经典(第二版)书上第三章习题所述题意而编写,并未严格按照原题的输入输出编写,代码仅经过个人测试(OJ网站太慢了).代码 ...
- 《算法竞赛入门经典——训练指南》第一章相关内容
#<算法竞赛入门经典--训练指南>第一章相关内容 希望各位大牛能指导! 红色为已经做了的...黄色背景是还有不懂地方,希望在年前能刷完第一章啊.... 更新版.google上貌似又加了ex ...
- 第一章 程序设计入门--算法竞赛入门经典
第一章 程序设计入门–算法竞赛入门经典 知识点一: int m=25; printf("%d\n",m); printf("%03d\n",m); 输出如下: ...
- #《算法竞赛入门经典》勘误
转自http://code.google.com/p/aoapc-book/wiki/BeginningAlgorithmContestsErrata #<算法竞赛入门经典>勘误 关于勘误 ...
- 算法竞赛入门经典——训练指南
<算法竞赛入门经典--训练指南> 基本信息 作者: 刘汝佳 陈锋 [作译者介绍] 丛书名: 算法艺术与信息学竞赛 出版社:清华大学出版社 ISBN:9787302291077 上架时间:2 ...
最新文章
- 释放变量所指向的内存_C++动态内存分配(学习笔记:第6章 15)
- TiDB 在小红书从 0 到 200+ 节点的探索和应用
- 无锡朗贤获B+轮融资,辰韬资本、兴韬投资领投
- OpenCV Error: Sizes of input arguments do not match (The operation is neither 'array op array' (wher
- ADO.NET 核心对象简介
- $_server['php_self'] 漏洞,Discuz! $_SERVER['PHP_SELF'] XSS Vulnerability
- Redis使用过程出现类型转换异常问题- 20190220
- 敏捷开发免费管理工具——火星人预览之五:常见问题问答
- Vlan配置详解之三层交换
- 考勤排班_考勤管理系统VS传统考勤排班优劣如何?
- Swf Decrypt详解
- xp系统简单tcpip服务器,XP系统怎样安装TCP/IP协议
- ps—图层、(移动工具中)对齐
- 挑食有理——罗敏娜集团总裁卓顺发养生之道
- 通过爬虫获取第五人格游戏信息整理并分析(一)
- 关于DoEvents
- BBR 拥塞控制算法blog笔记
- imvu为什么显示无法连接服务器,IMVU服务器错误怎么办 服务器无法连接解决办法...
- 【C++代码】区间重叠问题
- 清闲的工作与温水煮青蛙;-)
热门文章
- 简单来说一下java中的泛型,ssh中dao层使用会简化代码量
- (MoMoCMS教程11)页面的SEO优化与外链
- (转)用来理解Java的8个图表
- html多个盒子重叠浮动,如何让浮动后的多个盒子水平居中
- java Date days_Java中的LocalDate plusDays()方法
- ios获取新数据要不要关_ios获取新数据要不要关
- 判断是否是数组的方法
- Java黑皮书课后题第5章:5.12(求满足n方>12000的n的最小值)使用while循环找出满足n方大于12000的最小整数n
- Java黑皮书课后题第2章:*2.19(几何:三角形面积)编写程序,提示用户输入三角形的三个点(x1, y1)(x2, y2)(x3, y3),然后显示它的面积
- Linux shell去除字符串中所有空格