算法分析:
首先假设人无区别
令f(m,n)表示有m个人手持¥50的钞票,n个人手持¥100的钞票时共有的方案总数。则可以分以下情况讨论这个问题:
(1)当n=0时 n=0意味着排队购票的所有人手中拿的都是 ¥50的钞票,那么这m个人排队方案总数为1。
(2)当m<n时 显然,f(m,n)=0
(3)其他情况:
考虑(m+n)个人排队购票的情景,第(m+n)人站在第(m+n-1)个人的后面,则第(m+n )个人的排队方式可以由下列两种情况获得:
a.第(m+n )个人手持¥100的钞票,则在他之前的(m+(n-1))个人中有m个人手持¥50的钞票,有(n-1)个人手持¥100的钞票,此种情况共有f(m,n-1);
b.第(m+n )个人手持¥50的钞票,则在他之前的((m-1)+n)个人中有m-1个人手持¥50的钞票,有n个人手持¥100的钞票,此种情况共有f(m-1,n)
根据加法原理得到:
f(m,n)=f(m-1,n)+f(m,n-1)
于是得到f(m,n)的计算公式

人是有区别的,对于持有100和50 钞票的人分别进行全排列即为最后要的结果。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100;
int dp[N+5][N+5][500];
int ans[10000];
void bigadd(int m, int n) {
int i, len;
len = max(dp[m][n-1][0], dp[m-1][n][0]);
for (i = 1; i <= len; ++i)
dp[m][n][i] = dp[m][n-1][i] + dp[m-1][n][i];
for (i = 1; i <= len; ++i) {
if (dp[m][n][i] > 9) {
dp[m][n][i+1] += dp[m][n][i]/10;
dp[m][n][i] %= 10;
}
}
while (dp[m][n][i]) {
dp[m][n][i+1] += dp[m][n][i]/10;
dp[m][n][i] %= 10;
i++;
}
dp[m][n][0] = i - 1;
}
void init() {
int i, j;
for (i = 0; i <= N; ++i)
for (j = 0; j <= N; ++j) {
dp[i][j][0] = 1;
dp[i][j][1] = 0;
}
for (i = 0; i <=N; ++i)
dp[i][0][0] = dp[i][0][1] = 1;
for (i = 1; i <= N; ++i)
for (j = 1; j <= i; ++j) {
bigadd(i, j);
}
}
void multiply(int m, int n, int c) {
int i, len;
while(c) {
len = ans[0];
for(i = 1; i <= len; ++i) {
ans[i] *= c;
}
for(i = 1; i <= len; ++i) {
if (ans[i] > 9) {
ans[i+1] += ans[i]/10;
ans[i] %= 10;
}
}
while (ans[i]) {
ans[i+1] += ans[i]/10;
ans[i] %= 10;
i++;
}
ans[0] = i-1;
c--;
}
}
int main()
{
init();
int m, n, ca = 0;
while (scanf("%d %d", &m, &n) != EOF && (n!=0 || m!=0)) {
printf("Test #%d:\n", ++ca);
memcpy(ans, dp[m][n], sizeof(ans));
multiply(m, n, m);
multiply(m, n, n);
int i;
for (i = ans[0]; i >= 1; --i)
printf("%d", ans[i]);
printf("\n");
}
return 0;
}