问题 1163: 【排队买票】题目链接
题目描述
有M个小孩到公园玩,门票是1元。其中N个小孩带的钱为1元,K个小孩带的钱为2元。售票员没有零钱,问这些小孩共有多少种排队方法,使得售票员总能找得开零钱。注意:两个拿一元零钱的小孩,他们的位置互换,也算是一种新的排法。(M<=10)
输入
输入一行,M,N,K(其中M=N+K,M<=10).
输出
输出一行,总的排队方案。
样例输入
4 2 2
样例输出
8
题解:
很久之前看过这道题,没有思路,然后最近有碰到了,就想去做一下,看了题解重新来做。
通过变量sum判断这种排列是否有零钱找,
如果a[i]是1,sum++,
如果a[i]是2,sum–,
如果sum<0则这种排列不符合题目条件。
判断函数:
//定义sum记录收银员现在零钱的总数
//如果a[i]=1,收银员的零钱+1
//如果a[i]=2,收银员的零钱-1
int judge(int length){
int sum=0;
for(int i=0;i<length;i++){
if(a[p[i]]==1)//通过p记录的下标找a
sum++;
else
sum--;
if(sum<0)
break;
}
if(sum<0)//最终如果sum<0,返回0,否则返回1
return 0;
else
return 1;
}
定义a存储1元和2元的小孩
定义p存储深搜枚举的下标
定义v判断下标是否使用过
利用深搜全排列,枚举所有有可能的下标排列
全排列函数:
void dfs(int x){
if(x==m){//判断终止条件
if(judge(m)==1)
ans++;
return ;
}
for(int i=0;i<m;i++){
if(v[i]==0){//如果这个下标还没有加入排列
v[i]=1;
p[x]=i;//用P数组记录下标
dfs(x+1);//继续下一个排列
v[i]=0;
}
}
return ;
}
代码:
#include<iostream>
#include<string.h>
using namespace std;
int m,n,k;
int a[20],p[20],v[20];
//a记录分别有多少1元和多少2元,p记录下标枚举的结果,v记录该下标是否用过
int ans;
//定义sum记录收银员现在零钱的总数
//如果a[i]=1,收银员的零钱+1
//如果a[i]=2,收银员的零钱-1
int judge(int length){
int sum=0;
for(int i=0;i<length;i++){
if(a[p[i]]==1)//通过p记录的下标找a
sum++;
else
sum--;
if(sum<0)
break;
}
if(sum<0)//最终如果sum<0,返回0,否则返回1
return 0;
else
return 1;
}
void dfs(int x){
if(x==m){//判断终止条件
if(judge(m)==1)
ans++;
return ;
}
for(int i=0;i<m;i++){
if(v[i]==0){//如果这个下标还没有加入排列
v[i]=1;
p[x]=i;//用P数组记录下标
dfs(x+1);//继续下一个排列
v[i]=0;
}
}
return ;
}
int main(){
while(cin>>m>>n>>k){
//初始化
memset(a,0,sizeof(a));
for(int i=0;i<m;i++){
if(i<n)
a[i]=1;
else
a[i]=2;
}
ans=0;
//全排序
dfs(0);
cout<<ans<<endl;
}
return 0;
}