蓝桥杯:冰鞋借还排队问题(未名湖边的烦恼) 递归解法
问题描述
每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
每天早上,租鞋窗口都会排起长龙,假设有还鞋的m个,有需要租鞋的n个。现在的问题是,这些人有多少种排法,可以避免出现体育组没有冰鞋可租的尴尬场面。(两个同样需求的人(比如都是租鞋或都是还鞋)交换位置是同一种排法)
输入格式
两个整数,表示m和n
输出格式
一个整数,表示队伍的排法的方案数。
样例输入
3 2
样例输出
5
数据规模和约定
m,n∈[0,18]
思路
其实总共就是 【借】 和 【还】 两种状态,那么用二进制串(或者int数组)可以表示排队的状态,那么问题就变得很简单了
- 用 0 表示还冰鞋,用 1 表示借冰鞋
- 根据借还的人数 m,n 穷举所有长度为 m+n 的,0 的数量为m,1 的数量为n的 0-1 串(二进制串)
- 变量 num 表示持有的冰鞋数量,从串头开始遍历,如果遇到 0,num++,如果遇到 1,num–
- 如果遍历全程,每次操作后,数量num不为负数,则该序列为合法排队序列
完整代码
#include <iostream>
using namespace std;
int m, n; // 还,借的人数
int return_num; // 当前剩下多少人没还
int borrow_num; // 当前剩下多少人没借
int a[1000]; // int 数组表示 0 - 1 二进制串
int len = 0; // 串长度控制
int cnt = 0; // 合法排队序列计数器
void dfs()
{
// 如果所有人都完成操作,分析排队序列是否合法
if(len == m+n)
{
int num = 0; // 拥有冰鞋的数量
for(int i=0; i<n+m; i++)
{
if(a[i] == 0)
{
num += 1;
}
else
{
num -= 1;
}
if(num < 0)
{
break;
}
}
if(num >= 0)
{
cnt += 1;
}
return;
}
// 如果有人没完成操作,递归 + 状态重置
else
{
// 当前剩下 return_num 人没还
if(return_num > 0)
{
return_num -= 1;
a[len++] = 0;
dfs();
len--;
return_num += 1;
}
// 当前剩下 borrow_num 人没借
if(borrow_num > 0)
{
borrow_num -= 1;
a[len++] = 1;
dfs();
len--;
borrow_num += 1;
}
}
}
int main()
{
cin>>m>>n;
return_num = m;
borrow_num = n;
dfs();
cout<<cnt<<endl;
return 0;
}