oj之路(第一天)(续:由题目看思想)

我又来了,这是今天最后一道题咯~~作为新手,一天打这么多~这么久~的代码,还是真的觉得神疲力竭啊~

好了,接下来要说的一道题,应该只能说是一道数学题,不过数学题也是能够体现一些思想滴~~好好琢磨才是王道

===========================================================================================================

Description
    一天,OYY 从外面打完比赛回来,手上拿了很多个气球,颜色各不相同。他见到我,就说,你看,我拿了很多气球!
我膜拜死了!!然后他就问了我一个问题,如果把这里的气球分成若干份。有多少种分法呢?
    由于我数学非常菜,顿时头晕了,因此希望大家能帮我解答这个问题(@_@))
输入格式
输入数据有2行
第1 行有两个数n,m,分别代表oyy 手上的气球个数和分的份数(n<=10,m<=5)
第2 行有m 个数,分别代表每一份的个数,保证总个数等于n
输出格式
输出数据有1行,输出一个数代表不同分法的总数。
输入样例
3 1
3
输出样例
1
提示
Sample Input2:
4 2
2 2
Sample Output2:
3

===========================================================================================================

思考过程:学习过高中课程的大概都知道这种题的解法了吧,揭开那神秘的面纱,展现在眼前的就是--排列组合的问题
但是这里我想所说的是:
任何心里觉得有底气的题目就越是要小心仔细的思考一些细节,像我 抓狂还是被这道题目折磨了一段时间的。以下时要注意的问题,也是算法:
对组合的拆分要仔细分析,如果出现拆分出来的个数是一样的,那么直接进行全部组合的统计将会导致重复计数的情况(即直接用C几几这样的运算)
不过这样计算完也是没错的,只要接下来进行重复情况的去除就行了--这就是这道题的算法--先进行所有组合的统计,之后再来去除重复计数。

以上的算法基于这样一个定理:对一个数n进行平均拆分成m份(整数),那么结果会有这么多的情况(都不一样):Cnm / Amm(第一个在右下角,第二个在右上角)

所以想要去除重复计数就很简单了:
如果拆分时没有出现任何一样的份数(例如:1,2,3,4),那么就不用去除重复计数,因为压根就没有重复计数。
如果出现了重复计数m1份,m2份等等(例如:1,1,3,3),那么把结果除以m1的阶乘,m2的阶乘等等就得到答案了。

===========================================================================================================

#include <stdio.h>
int C(int a, int b)
{
	int tmp = 1;
	for (int i = 1; i <= a; ++i)
		tmp *= b--;
	for (int i = 1; i <= a; ++i)
		tmp /= i;
	return tmp;
}
int fact(int div)
{
	int sum = 1;
	while (div)
		sum *= div--;
	return sum;
}
int main()
{
	int sum = 1;
	int n, m, mt[5] = { 0 };
	scanf("%d%d", &n, &m);
	for (int i = 0; i < m; ++i) {
		scanf("%d", &mt[i]);
	}
	for (int i = 0; i < m; ++i) {
		sum *= C(mt[i], n);
		n -= mt[i];
	}

	for (int i = 0; i < 4; ++i) {
		int divisor = 1;
		for (int j = i + 1; j < 5 && mt[i] != 0; ++j) {
			if (mt[i] == mt[j]) {
				divisor++;
				mt[j] = 0;
			}
		}

		sum /= fact(divisor);

	}
	printf("%d\n", sum);
	return 0;
}

===========================================================================================================


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值