vijos1060 盒子(重庆一中高2018级信息学竞赛测验7) 解题报告
来源:互联网 发布:人工智能计算器3.8.1版 编辑:程序博客网 时间:2024/05/02 04:34
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
答案不超过2^64-1
做题思路(错解):拿到这道题,审题时不仔细,把一个盒子可以同时放进两种球,也可以只放一种看成一个盒子可以同时放进两个球,也可以只放一个,然后就以为一个盒子最多只能放两个球,从而推出了错误的递推方程。
解题思路(正解):根据题意,要求方案总数,自然想到递推算法,但在设计状态函数时有不同的设法。
第一种,也是最容易想到的,求什么设什么,设f(i,j,k)表示前i个盒子最多放j个红球,k个蓝球的方案数,分析前i个盒子时,第i个盒子可以不放球,可以只放一个红球,也可以只放一个蓝球,……,最多可以放j个红球和k个蓝球,此时相对的前i-1个盒子可以最多放j个红球和k个蓝球,可以最多只放j-1个红球和k个蓝球,可以最多只放j个红球和k-1个蓝球,……,最少可以不放球(每种情况分别与前面第i个盒子放球情况相对应),则递推方程为f(i,j,k)=∑f(i-1,j-x,k-y)(0<=x<=j,0<=y<=k)。边界条件为f(0,j,k)=1,即不选盒子,最多放j个红球,k个蓝球的方案数是1(不放球)。答案即为f(n,A,B),该种算法的时间复杂度为O(n*A*B*A*B)。
第二种,是更高级且可以针对更大的数据规模的设法,因为盒子中放红球和放蓝球不相互影响,即假设你先放1个红球,之后你可以放0,1,2,...,B个蓝球,如果你放2个红球,之后你仍可以放0,1,2,...,B个蓝球,所以可以设f(i,j)表示前i个盒子最多放j个球的方案数,分析前i个盒子时,第i个盒子可以不放,可以放1个,最多放j个,此时相对的前i-1个盒子可以最多放j个,可以最多放j-1个,最少可以不放,则递推方程为f(i,j)=∑f(i-1,j-x)(0<=x<=j)。边界条件为f(0,j)=1,即不选盒子,最多放j个球只有一种方案(不放球)。因为对于每个红球的选择,都有B个蓝球的选择,所以答案为f(n,A)*f(n,B),并且在计算f(i,j)时,可以先设一个参数t记录当前f(i-1,j-x)的和,就可以省去枚举x,则此算法的时间复杂度O(n*max(A,B))。
需要注意的是,该题的答案最多为2^64-1(不是2^63-1),不能用long long,要用unsigned long long。
解法1:
#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>using namespace std;const int maxn=25;int N,A,B;/*f(i,j,k)表示前i个盒子最多放j个红球,k个蓝球的方案数f(i,j,k)=f(i-1,j,k)+f(i-1,j-1,k)+f(i-1,j,k-1)+...+f(i-1,0,0) 边界:f(0,j,k)=1*/unsigned long long d[25][20][20];void solve() //递推算法{memset(d,0,sizeof(d)); //初始化for(int j=0;j<=A;j++)for(int k=0;k<=B;k++)d[0][j][k]=1; //边界for(int i=1;i<=N;i++)for(int j=A;j>=0;j--)for(int k=B;k>=0;k--)for(int x=0;x<=j;x++)for(int y=0;y<=k;y++)d[i][j][k]+=d[i-1][j-x][k-y];cout<<d[N][A][B]<<'\n';}int main(){//freopen("box.in","r",stdin);//freopen("box.out","w",stdout);scanf("%d%d%d",&N,&A,&B);solve();return 0;}
解法2:
#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<cstring>using namespace std;const int maxn=25;int N,A,B;/*f(i,j)表示前i个盒子最多放j个球的方案数f(i,j)=f(i-1,j)+f(i-1,j-1)+...+f(i-1,0) 边界:f(0,j)=1*/unsigned long long d[25][20];void solve() //递推算法{memset(d,0,sizeof(d)); //初始化for(int j=0;j<=max(A,B);j++)d[0][j]=1; //边界for(int i=1;i<=N;i++){unsigned long long t=0; //记录和for(int j=0;j<=max(A,B);j++){t+=d[i-1][j];d[i][j]=t;}}cout<<d[N][A]*d[N][B]<<'\n';}int main(){//freopen("box.in","r",stdin);//freopen("box.out","w",stdout);scanf("%d%d%d",&N,&A,&B);solve();return 0;}
考后反思:审题时一定要仔细啊,看错一个字就可能会丢很多分。
- vijos1060 盒子(重庆一中高2018级信息学竞赛测验7) 解题报告
- vijos1037 搭建双塔(重庆一中高2018级信息学竞赛测验7) 解题报告
- UVA1615 高速公路(highway)(重庆一中高2018级信息学竞赛测验5) 解题报告
- RQNOJ190 拦截匪徒 (重庆一中高2018级信息学竞赛测验2) 解题报告
- UVA815 洪水(重庆一中高2018级信息学竞赛测验3) 解题报告
- POJ3069 萨鲁曼的大军(重庆一中高2018级信息学竞赛测验3) 解题报告
- 练习题GRYZ2015 足球联赛(重庆一中高2018级信息学竞赛测验4) 解题报告
- 练习题 旅行(重庆一中高2018级信息学竞赛测验4) 解题报告
- POJ3045 牛的杂技(重庆一中高2018级信息学竞赛测验4) 解题报告
- POJ3622 挑剔的美食家(重庆一中高2018级信息学竞赛测验5) 解题报告
- vijos1488 路灯改建计划(重庆一中高2018级信息学竞赛测验9) 解题报告
- Codevs4175 收费站(重庆一中高2018级信息学竞赛测验9) 解题报告
- 【动态规划练习题】 学生宿舍(重庆一中高2018级信息学竞赛测验10) 解题报告
- JSOI2010 Codevs5227 盛夏的果实(重庆一中高2018级信息学竞赛测验7) 解题报告
- 复赛模拟试题 物品选取(重庆一中高2018级信息学竞赛测验7) 解题报告
- USACO2.4.2 穿越栅栏(简单版本) (重庆一中高2018级信息学竞赛测验2) 解题报告
- UVA1625 颜色的长度(color length)(重庆一中高2018级信息学竞赛测验10) 解题报告
- USACO 月赛 劣质的草 (重庆一中高2018级信息学竞赛测验2) 解题报告
- Java反射第一课认识Class类
- Impala 教程
- LintCode字符串题总结
- iOS取小数精度
- Windows进程间通信的各种方法
- vijos1060 盒子(重庆一中高2018级信息学竞赛测验7) 解题报告
- Linux进程间通信--匿名管道
- 给Django后台富文本编辑器添加上传文件的功能
- Navicat Premium链接到Oracle,,,我的解决路线
- Markdown 语法说明 (简体中文版)
- Android 上传图片和文本数据到服务器
- A*方法
- Android中自动跳转到系统设置界面
- tcp_tw_reuse、tcp_tw_recycle 使用场景及注意事项