【组合数学】购票问题

购票问题

    题目大意:一张票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);
}

  

posted @ 2016-12-11 14:54  wxjor  阅读(1664)  评论(0编辑  收藏  举报