题目 1163: 排队买票

题目描述

题目描述
有M个小孩到公园玩,门票是1元。其中N个小孩带的钱为1元,K个小孩带的钱为2元。售票员没有零钱,问这些小孩共有多少种排队方法,使得售票员总能找得开零钱。注意:两个拿一元零钱的小孩,他们的位置互换,也算是一种新的排法。(M<=10)

输入
输入一行,M,N,K(其中M=N+K,M<=10).

输出
输出一行,总的排队方案。

样例输入
4 2 2
样例输出
8

思路:

我开始做的时候有些不理解,网上的大部分题解是关于卡特兰数的(不用说,我看不懂hah)

然后我就在想这个问题,起初我想用回溯法插入元素,不过最后放弃了,太复杂了。

然后我就想这个排队是什么时候是合法的,很好想出来,就是每个2前面至少对应着一个1。话虽如此但我们如何检验?我起初想暴力解决但实现起来思路比较复杂,而且时间复杂度高。

然后我突然想到了多数元素的摩尔投票法,然后我就想到了用一个num记录,num如果有1就++,有2就–,如果过程中num<0则证明存在有一个2没有一个1对应。

但是到此为止还没有结束,我想的是判断类似1122的所有全排列包括重复的。(这种应该可以回溯写出来,但是感觉还是比较复杂的),然后我就改成初始前面的1为0K-1,后面的2为KN-1 所以小于K的就相当于是1了,大于K的就相当于是2了。对于这种0123的序列我们可以直接使用next_permutation();

参考ac题解

#include <iostream>
#include <algorithm>
using namespace std;
int N, K, M;

int main() {
	while (cin >> N >> K >> M) {
		int a[N], res = 0;
		for (int i=0; i<K; i++) {
			a[i] = i;
		}
		for (int i=K; i<N; i++) {
			a[i] = i;
		}
		do {
			int flag = 0;
			// check每个全排列, num务必要初始化 
			int num = 0;
			for (int i=0; i<N; i++) {
				if (a[i] >= K) {
					num--;
				} else {
					num++;
				}
				if (num < 0) {
					flag = 1;
					break;
				}
			}
			if (flag == 0) {
//				for (int i=0; i<N; i++) {
//					cout << a[i];
//				}
//				cout << "\n";
				res++;
			}
			
		} while (next_permutation(a,a+N));
	
	
		cout << res << "\n";
	}
	return 0;
}

思路可能不成熟,如有错误,还望指正

好久没写题解了!有点衰了,加油呀大家

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值