购票问题
题目大意:一张票50元,有N个带着50元的人和N个带着100元的人,请问总共有多少种排队方法使得不会出现购票找不回钱的尴尬局面?
输入样例:2
输出样例:2
这是一类非常有代表性的问题,下面将介绍该问题的5种解法
Number 5:暴力枚举
很显然,要使带着100元的购票那么就需要50的去找给他。
那么可以抽象的看做当50元购票时50元的票数+1
而当100元购票时50元的票数-1
又因为100元的并不能找钱用,所以可以不做考虑……
那么很容易可以看出我们在收取一个人50元的时候50元的个数可以+1
所以定义一个计数变量k
那么我们可以决定此时是选择50的人来买票或者是100的人来买票。
因为50找100,他们都有N个,则互相抵消。
最后可以直接看k是否==0
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int N;
int k;
int ans;
void dfs(int tmp){//回溯
if(tmp==2*N){//如果全排完了
if(!k) ans++;//满足出现了N个100 N个50答案数+1
return ;
}
if(k){//如果还有50的
k--;//就可以让100的来
dfs(tmp+1);//深入
k++;//恢复
}
k++;//在加一个50的显然不成问题
dfs(tmp+1);//搜索
k--;
}
int main(){
cin>>N;
dfs(0);
cout<<ans;
}
Number 4:栈模型
此类算法就是生成一串排列并在中途判断
时间复杂度>Number 5
空间复杂度>Number 5
代码复杂度>Number 5
思考复杂度>Number 5
编码复杂度>Number 5
你说我还讲它干嘛?
Number 3:DFS(递归)
我们可以把问题分为3个阶段:
其中a代表50张数,b代表100张数
①不满足条件类型
1.当a<b时
2.当a>N时
3.当b>N时
②当a==b==N时
全都符合条件,答案数+1
③直接继续搜索
代码如下:
#include<iostream>
using namespace std;
int cnt,n;
void dfs(int a,int b)
{
if(a<b||a>n||b>n) return ;
else if(a==n&&b==n) cnt++;
else{dfs(a,b+1);dfs(a+1,b);}
}
int main()
{
cin>>n;
dfs(0,0);
cout<<cnt;
}
Number 2:动态规划or记忆化搜索
参见Number 3,思想基本上相同,较好理解
#include<iostream>
using namespace std;
inline int read()
{
int x,f=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0');
return x*f;
}
inline void write(int x){
if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
}
long long dp[100][100];
int a,b,n;
int main()
{
n=read();
dp[0][0]=1;
for(a=1;a<=n;a++)
for(b=0;b<=a&&b<=n;b++)
{
if((b==n||b==a)&&a==n)dp[a][b]=dp[a-1][b]+dp[a][b-1]+1;
else dp[a][b]=dp[a-1][b]+dp[a][b-1];
}
write(dp[n][n]-1);
}
Number 1:卡特兰数
答案数=C(2n,n)/(n+1)
答案数可以看做为总排列数-不符合要求数
而可以看出总排列数为2N里面选N个,那么就是C(2N,N)
可以抽象的看做当50元购票时50元的票数+1
而当100元购票时50元的票数-1
也就是50的个数要始终≥100的个数
不符合条件的就是在一段里面有m+1个100元
有m个50元
那么可以看做是从2N个里面选择N+1个
即C(2n,n+1)
C(2N,N)-C(2N,N+1)=C(2N,N)/(N+1)
代码如下:
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
long long ans=1;
for(int i=0;i<n;i++)
ans=ans*(2*n-i)/(i+1);
cout<<ans/(n+1);
}