试题 算法训练 未名湖边的烦恼
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
资源限制
内存限制:256.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)
输入格式
两个整数,表示m和n
输出格式
一个整数,表示队伍的排法的方案数。
样例输入
3 2
样例输出
5
数据规模和约定
m,n∈[0,18]
问题分析
根据题目的样例输入,我们具体分析他是如何形成最终结果的,
首先,题目只有还鞋的人3个,借鞋的人2个,所以此处我们需要逆推(正推也可以)
具体分析为:
先假设最后一人为还鞋的人,此后出现2个分支,
一:倒数第二个人为还鞋的人,此时剩余还鞋的人只有一人,而此时还有2人要借鞋,剩余还鞋的人少于借鞋的人,方法不可行,结束
二:倒数第二个人为借鞋的人,此时还有2人要还鞋,剩余借鞋的人只有一人,方法可行,进入下一步判断
{
(1)倒数第三个人为还鞋的人,此时剩余还鞋的人只有一人,此时有1人要借鞋,方法可行,进入下一步判断
{
(1)倒数第四个人为还鞋的人,此时剩余还鞋的人只有0人,此时有1人要借鞋,剩余还鞋的人少于借鞋的人,方法不可行,结束
(2)倒数第四个人为借鞋的人,此时还有1人要还鞋,剩余借鞋的人有0人,方法可行,此时借鞋人数的为0,而前面的一定是还鞋的人,所以sum+1,结束
}
(2)倒数第三个人为借鞋的人,此时剩余还鞋的人有2人,此时有0人要借鞋,方法可行,此时借鞋的人数为0,而前面的一定是还鞋的人,所以sum+1,结束
}
此时,存在2种方法,sum=2;
再假设最后一人为借鞋的人,此后出现2个分支,
一:倒数第二个人为还鞋的人,此时剩余还鞋的人有2人,此时还有1人要借鞋,方法可行,进入下一步判断
{
(1)倒数第三个人为还鞋的人,此时剩余还鞋的人只有一人,此时有1人要借鞋,方法可行,进入下一步判断
{
(1)倒数第四个人为还鞋的人,此时剩余还鞋的人只有0人,此时有1人要借鞋,方法不可行,结束
(2)倒数第四个人为借鞋的人,此时还有1人要还鞋,剩余借鞋的人有0人,方法可行,此时借鞋人数的为0,而前面的一定是还鞋的人,所以sum+1,结束
}
(2)倒数第三个人为借鞋的人,此时剩余还鞋的人有2人,此时有0人要借鞋,方法可行,此时借鞋的人数为0,而前面的一定是还鞋的人,所以sum+1,结束
}
二:倒数第二个人为借鞋的人,此时还有3人要还鞋,剩余借鞋的人有0人,此时借鞋人数的为0,而前面的一定是还鞋的人,所以sum+1,结束
此时存在三种方案,sum=5
(sum用于记录统计方法,其初始值为0)
具体代码如下:
#include <iostream>
using namespace std;
int sum=0,m,n;//sum用于记录可行方法总数
void fact(int x,int y)//此处递归为由后往前推,从后向前确定此人是还鞋还是借鞋
{
if(y==0 && x>=y)//首先第一步判断,是否存在剩余借鞋的人没了并且此时剩余还鞋的人要多于或等于剩余借鞋的人,如果此时成立,则前面剩余的人均为还鞋的人,此时方案一定成立,对sum+1
{
sum++;
return ;
}
if(x<y)//如果存在还鞋的人少于借鞋的人,此时鞋不够,该方案不可行,直接结束该次递归
{
return ;
}
fact(x-1,y);//假设最后一个人为还鞋的人(注意每次递归时由上个人已经确定,故只需考虑前面的人,最后一人为这前面的人的最后一位)
/*
例子:m=3 n=2
先假设最后一人为还鞋的人,此后出现2个分支,
一:倒数第二个人为还鞋的人,此时剩余还鞋的人只有一人,而此时还有2人要借鞋,剩余还鞋的人少于借鞋的人,方法不可行,结束
二:倒数第二个人为借鞋的人,此时还有2人要还鞋,剩余借鞋的人只有一人,方法可行,进入下一步判断
{
(1)倒数第三个人为还鞋的人,此时剩余还鞋的人只有一人,此时有1人要借鞋,方法可行,进入下一步判断
{
(1)倒数第四个人为还鞋的人,此时剩余还鞋的人只有0人,此时有1人要借鞋,剩余还鞋的人少于借鞋的人,方法不可行,结束
(2)倒数第四个人为借鞋的人,此时还有1人要还鞋,剩余借鞋的人有0人,方法可行,此时借鞋人数的为0,而前面的一定是还鞋的人,所以sum+1,结束
}
(2)倒数第三个人为借鞋的人,此时剩余还鞋的人有2人,此时有0人要借鞋,方法可行,此时借鞋的人数为0,而前面的一定是还鞋的人,所以sum+1,结束
}
此时,存在2种方法,sum=2;
*/
fact(x,y-1);//假设最后一个人为借鞋的人
/*
再假设最后一人为借鞋的人,此后出现2个分支,
一:倒数第二个人为还鞋的人,此时剩余还鞋的人有2人,此时还有1人要借鞋,方法可行,进入下一步判断
{
(1)倒数第三个人为还鞋的人,此时剩余还鞋的人只有一人,此时有1人要借鞋,方法可行,进入下一步判断
{
(1)倒数第四个人为还鞋的人,此时剩余还鞋的人只有0人,此时有1人要借鞋,方法不可行,结束
(2)倒数第四个人为借鞋的人,此时还有1人要还鞋,剩余借鞋的人有0人,方法可行,此时借鞋人数的为0,而前面的一定是还鞋的人,所以sum+1,结束
}
(2)倒数第三个人为借鞋的人,此时剩余还鞋的人有2人,此时有0人要借鞋,方法可行,此时借鞋的人数为0,而前面的一定是还鞋的人,所以sum+1,结束
}
二:倒数第二个人为借鞋的人,此时还有3人要还鞋,剩余借鞋的人有0人,此时借鞋人数的为0,而前面的一定是还鞋的人,所以sum+1,结束
此时存在三种方案,sum=5
*/
}
int main()
{
cin>>m>>n;//让用户输入还鞋的人m个,借鞋的人n个
fact(m,n);//进入递归
cout<<sum;//最后输出可行方法数量
return 0;
}
如有更好方法和疑惑,欢迎大家评论交流,谢谢大家!