有鱼丸M个,肉丸N个,碗K个。现将鱼丸和肉丸分放到这些碗里,碗可以是空的(什么也不放)。每个碗可以装的丸子数量不限,所有的碗是一样的,同一个碗里不能既有鱼丸又有肉丸。求有多少种放法。这里1<=M,N,K<=50。
例如,当N=M=1,K=3时,只有一种放法,因为(1,1,0), (1,0,1), (0,1,1)视为同一种。最后输出的结果要求取10000的余数,如结果为123456,则只需输出3456。
注:题目是博主回忆的,表达上与原题可能略有不同,但应该没有歧义。
题目提供了代码模板:
/** 请完成下面这个函数,实现题目要求的功能 **/
/** 当然,你也可以不按照这个模板来作答,完全按照自己的想法来 ^-^ **/
int ballAllocate(int m, int n, int k) {
}
int main() {
int res;
int _m;
cin >> _m;
cin.ignore(std::numeric_limits::max(), '\n');
int _n;
cin >> _n;
cin.ignore(std::numeric_limits::max(), '\n');
int _k;
cin >> _k;
cin.ignore(std::numeric_limits::max(), '\n');
res = ballAllocate(_m, _n, _k);
cout << res << endl;
return 0;
}
这里提供博主的解题思路,仅供参考,如有错误欢迎大家指出。如有更好的方法也希望有好心人能告知博主。
首先分析题目意思可以知道,这个问题其实鱼丸和肉丸是独立的。分鱼丸不影响肉丸,分肉丸不影响鱼丸。所以总的方法数应当由分鱼丸的方法数乘以分肉丸的方法数得到。考虑到这里的碗是一样的,我们只需要求一个有序的序列,比如3个鱼丸2个碗,只需要求出(1,2),不必再考虑(2,1)的情况。
所以问题转化为求一种丸子的有序分配方法数。假设结果按丸子数不减的序列排列,实现一个非空的丸子分配函数:
int ballAllocateNotEmpty(int n, int k, int upBound) {
int result = 0;
if (k == 1) {//只有一个碗
if (n <= upBound) {//丸子数不超过上限
result = 1;//有一种分法
} else {//丸子数超过上限,不满足有序序列
result = 0;//该分法不成立
}
} else {//有多个碗
if (n < k) {//丸子数小于碗数,必出现空碗
result = 0;//该分法不满足
} else if (n == k) {//丸子数等于碗数
result = 1;//只有一种分法,每个碗里放1个
} else {
for (int i = upBound; i > 0; i--) {//取一个碗,碗里可能放[1,upBound]个丸子
//当前碗里放i个丸子,剩余k-1个碗分配剩下的n-i个丸子,每个碗里丸子上限i个
result += ballAllocateNotEmpty(n - i, k - 1, i);
}
}
}
return result;
}
其中n表示n个丸子,k表示k个碗,upBound表示一个碗里的丸子数量上限,返回有几种分法,不出现空碗。
有了单独的分丸子函数后,再分配鱼丸和肉丸就只简单了:
int ball2AllocateNotEmpty(int m, int n, int k) {
int result = 0;
for (int i = 1; i < k; i++) {
int result_yuwan = ballAllocateNotEmpty(m, i, m);//i个碗放鱼丸
int result_rouwan = ballAllocateNotEmpty(n, k - i, n);//k-i个碗放肉丸
result += result_yuwan * result_rouwan;
}
return result;
}
m表示鱼丸数,n表示肉丸数,k表示碗数。按照(鱼丸,肉丸)分别分配到(1,k-1),(2,k-2)…(k-1,1)个碗中的方法数求和即得分配两种丸子的方法数(这里同样不出现空碗)。
最后,我们求整个分配过程的总方法数(包括出现空碗的情况)。按照空碗的数量分别对方法数进行求和:
int ballAllocate(int m, int n, int k) {
int total = 0;
for (int i = 0; i < k; i++) {
total += ball2AllocateNotEmpty(m, n, k - i);//i个空碗,k-i个非空碗
}
return total % 10000;//结果按要求取余
}
#include
using namespace std;
int ballAllocateNotEmpty(int n, int k, int upBound) {
int result = 0;
if (k == 1) {//只有一个碗
if (n <= upBound) {//丸子数不超过上限
result = 1;//有一种分法
} else {//丸子数超过上限,不满足有序序列
result = 0;//该分法不成立
}
} else {//有多个碗
if (n < k) {//丸子数小于碗数,必出现空碗
result = 0;//该分法不满足
} else if (n == k) {//丸子数等于碗数
result = 1;//只有一种分法,每个碗里放1个
} else {
for (int i = upBound; i > 0; i--) {//取一个碗,碗里可能放[1,upBound]个丸子
//当前碗里放i个丸子,剩余k-1个碗分配剩下的n-i个丸子,每个碗里丸子上限i个
result += ballAllocateNotEmpty(n - i, k - 1, i);
}
}
}
return result;
}
int ball2AllocateNotEmpty(int m, int n, int k) {
int result = 0;
for (int i = 1; i < k; i++) {
int result_yuwan = ballAllocateNotEmpty(m, i, m);//i个碗放鱼丸
int result_rouwan = ballAllocateNotEmpty(n, k - i, n);//k-i个碗放肉丸
result += result_yuwan * result_rouwan;
}
return result;
}
/** 请完成下面这个函数,实现题目要求的功能 **/
/** 当然,你也可以不按照这个模板来作答,完全按照自己的想法来 ^-^ **/
int ballAllocate(int m, int n, int k) {
int total = 0;
for (int i = 0; i < k; i++) {
total += ball2AllocateNotEmpty(m, n, k - i);//i个空碗,k-i个非空碗
}
return total % 10000;//结果按要求取余
}
int main() {
int res;
int _m;
cin >> _m;
cin.ignore(std::numeric_limits::max(), '\n');
int _n;
cin >> _n;
cin.ignore(std::numeric_limits::max(), '\n');
int _k;
cin >> _k;
cin.ignore(std::numeric_limits::max(), '\n');
res = ballAllocate(_m, _n, _k);
cout << res << endl;
return 0;
}