Vijos 1060 盒子(DP)

来源:互联网 发布:淘宝保健品代理 编辑:程序博客网 时间:2024/06/05 22:50

【问题描述】

  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]);}
0 0