题目描述
题目描述
有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;
}
思路可能不成熟,如有错误,还望指正
好久没写题解了!有点衰了,加油呀大家