时间限制: 1Sec 内存限制: 128MB
题目描述
一个实验室有N个放化学品的试管,排列在一条直线上。如果连续M个试管中放入药品,则会发生爆炸,于是,在某些试管中可能不放药品。
任务:对于给定的N和M,求不发生爆炸的放置药品的方案总数
输入
第一行是一个正整数L,代表输入数据的组数
接下来L行,每行有两个正整数N,M( 1<N<32,2≤M≤5)
输出
输出L行,每行只有一个正整数S,表示对应输入数据的方案总数。
样例输入
2
4 3
3 2
样例输出
13
5
Code
Code 1 错误50%
错误原因,多种情况少算
如下面情况
n=6 m=3
位置 1 2 3 4 5 6
摆放 1 1 1 1
#include<stdio.h>
//阶乘器
int Factorial(int n)
{
if(n<=1) return 1;
int result=1,i;
for(i=2;i<=n;i++)
result*=i;
return result;
}
//数学函数C
int FC(int n,int m)
{
if(!m) return 1;
int i,result=1;
for(i=n;i>n-m;i--)
result*=i;
return result/Factorial(m);
}
int main()
{
int L,m,n,i,count=0;
scanf("%d", &L);
while(L--){
scanf("%d%d", &n,&m);
//注意此处的count初始化
for(i=0,count=0;i<=m&&i<=n;i++){
if(i==m) count+=FC(n,i)-FC(n-i+1,1);
else count += FC(n, i);
}
printf("%d\n", count);
}
return 0;
}
Code 2【借鉴】
n=0 m=3 0
n=1 m=3 0 1 /2
n=2 m=3 0 1 2 12 /4
n=3 m=3 0 1 2 3 12 13 23 /7 123
n=4 m=3 0 1 2 3 4 12 13 14 23 24 34 124 134 /13 234
n=5 m=3 0 1 2 3 4 5 12 13 14 15 23 24 25 34 35 45 124 125 134 135 145 235 245 1245 /24 345 1345
可以看出
第n=3比n=2多出一个123
第n=4比n=3多出一个234
第n=4比n=4多出一个345和1345
分为三种情况:
第一种:n<m
此时可以随便放,每个试管共有2种,所以共有2n情况
第二种:n=m
此时爆炸的情况只有一种,即全部试管都放药剂。
总情况有2n-1
第三种:n>m
思考方式为:在n-1个试管的基础上再在最后放一个试管
1.最后一个试管不放药剂,前n-1个试管的摆放情况通过递归可以求得ia[n-1][m]
2.最后一个试管放药剂,此时需要排除会爆照的情况,即n,n-1,n-2...n-m+1
(共m-1个试管)都放药的情况
为什么是m-1个试管?
因为在n-1的基础上是都不会爆照的,所以在最后增加一个有药的试管时,爆炸的原因只可能是前面有m-1个有药的试管
前面有一个有药的试管和后面m-1个试管中间肯定有没药的将其分开。
关键是怎么求这种会爆炸的情况?
首先是以n-1的情况为基础的,然后将最后m-1个去掉,此时共有n-m个试管,因为中间至少必有一个试管将前面一个有药剂的试管和后面m-1个有药剂的试管分开,而且这个试管一定和后面的m-1个试管连在一起的。
根据最后m个试管的情况,就确定了前面试管一定不会爆炸。
然后根据递归函数的功能:就可以得出前面n-m-1个试管不会爆照的放药剂的情况ia[n-m-1][m]
所以第三种情况的总情况数为:2*ia[n-1][m]-ia[n-m-1][m]
注:如果n-m-1=0的情况下,返回的是1
#include<stdio.h>
#include<string.h>
#include<math.h>
//进行排列
int Arrange(int ia[][6],int n,int m)
{
if(ia[m][n]) return ia[m][n];//记忆数组
if(m==n){
ia[m][n]=(int)pow(2,n)-1;//除去全部都有试剂的情况
return ia[m][n];
}
if(n<m){
ia[m][n]=(int)pow(2,n);
return ia[m][n];
}
//n>m
//在n-1个试管的基础上再在最后放一个试管
//1.最后一个试管不放药剂,前n-1个试管的摆放情况通过递归可以求得ia[n-1][m]
//2.最后一个试管放药剂,此时需要排除会爆照的情况,即n,n-1,n-2...n-m+1(共m-1个试管)都放药的情况
return Arrange(ia,n-1,m)+ Arrange(ia, n-1, m)- Arrange(ia, n-m-1, m);
}
int main()
{
int L,ia[33][6],n,m;//int array-->ia
scanf("%d", &L);
while(L--){
memset(ia,0,sizeof(ia));//initialize
scanf("%d%d", &n,&m);
printf("%d\n",Arrange(ia,n,m));
}
return 0;
}