zoukankan      html  css  js  c++  java
  • 【组合数学】购票问题

    购票问题

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

      

  • 相关阅读:
    【权限维持】window几种隐藏技术
    Flash XSS 漏洞实例
    nginx_lua_waf 部署、测试记录
    WAF Bypass数据库特性(Access探索篇)
    WAF Bypass数据库特性(MSsql探索篇)
    WAF Bypass数据库特性(Mysql探索篇)
    WAF Bypass数据库特性(Oracle探索篇)
    WAF Bypass 笔记(SQL注入篇)
    如何关闭Struts2的webconsole.html
    Windows Server 2008 R2 WSUS服务器的详细配置和部署
  • 原文地址:https://www.cnblogs.com/wxjor/p/6159630.html
Copyright © 2011-2022 走看看