【问题描述】
n 个盒子排成一行(编号为1..n)。你有A个红球和B个蓝球。球除了颜色没有任何区别。你可以将球放进盒子。一个盒子可以同时放进两种球,也可以只放一种,也可以空着。球不必全部放入盒子中。编程计算有多少种放置球的方法。
【输入格式】
一行,n,A,B,用空格分开。
【输出格式】
一行,输出放置方案总数。
【输入样例】
2 1 1
【输出样例】
9
【样例解释】
用一对括号表示一个盒子,R表示红色,B表示蓝色,有如下9种方案:
( ), ( )
(R ), ( )
(B ), ( )
(RB), ( )
(R ), (B )
(B ), (R )
( ), (R )
( ), (B )
( ), (RB)
【数据范围】
1<=n<=20 , 0<=A<=15, 0<=B<=15
这道题计算多少种放置球的方法,一个盒子里可以放多个球。可以设状态函数f(i,j,k)代表前i个箱子里放j个红球,k个蓝球的方案数。此时的方程f(i,j,k)=
Σ
f(i-1,j-x,k-y)(0<=x<=j&&0<=y<=k),边界为f(0,0,0)=1(前0个箱子里放0个红球,0个蓝球的方案数为1),用五重循环实现,最后的答案就是f(n,a,b)=
Σ
f(i-1,x,y)(0<=x<=j&&0<=y<=k)。时间复杂度为a*a*b*b*n.因为答案最大达到2^64-1,所以记得用unsigned long long。
如果要优化,可以设状态函数f(i,j)代表前i个箱子里放j个蓝球或红球的方案数,把蓝球和红球单独放,方程为f(i,j)=
Σ
f(i-1,j-k)(0<=k<=j),边界是f(i,0)=1,f(0,i)=1。最后答案为f(n,a)*f(n,b)。此时时间复杂度为(max(a,b)^2*n/2)。
如果只用两重循环,可以把t初始化放在循环外,每次循环j时t累加一边f(i-1,j),最后f(i,j)转存t。时间复杂度为(max(a,b)*n)。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a,b,n;
unsigned long long d[22][22];
//f(i,j)前i个箱子装只放红球或蓝球不超过j球的方案数
//f(i,j)=f(i-1,0)+f(i-1,k) 0<=k<=a||k<=b;
int main()
{
//freopen("box.in","r",stdin);
scanf("%d %d %d",&n,&a,&b);
memset(d,0,sizeof(d));
for(int i=0;i<=n;i++)
{
d[i][0]=1;
}
for(int i=1;i<=a||i<=b;i++)
{
d[0][i]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=a||j<=b;j++)
{
unsigned long long t=0;
for(int k=0;k<=j;k++)
{
t+=d[i-1][k];
}
d[i][j]=t;
}
}
printf("%I64u",(unsigned long long)d[n][a]*d[n][b]);
}