蓝桥杯:冰鞋借还排队问题(未名湖边的烦恼) 递归解法

蓝桥杯:冰鞋借还排队问题(未名湖边的烦恼) 递归解法

问题描述

每年冬天,北大未名湖上都是滑冰的好地方。北大体育组准备了许多冰鞋,可是人太多了,每天下午收工后,常常一双冰鞋都不剩。
  每天早上,租鞋窗口都会排起长龙,假设有还鞋的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;
}


发布了18 篇原创文章 · 获赞 0 · 访问量 129

猜你喜欢

转载自blog.csdn.net/weixin_44176696/article/details/103987811
今日推荐