【题解】球迷购票问题-C++

题目背景
盛况空前的足球赛即将举行。球赛门票售票处排起了球迷购票长龙。

按售票处规定,每位购票者限购一张门票,且每张票售价为50元。在排成长龙的球迷中有N个人手持面值50元的钱币,另有N个人手持面值100元的钱币。假设售票处在开始售票时没有零钱。试问这2N个球迷有多少种排队方式可使售票处不致出现找不出钱的尴尬局面。

题目描述
例如当n=2是,用A表示手持50元面值的球迷,用B表示手持100元钱的球迷。则最多可以得到以下两组不同的排队方式,使售票员不至于找不出钱。

第一种:A A B B

第二种:A B A B

[编程任务]

对于给定的n (0≤n≤20),计算2N个球迷有多少种排队方式,可以使售票处不至于找不出钱。

输入输出格式
输入格式:
一个整数,代表N的值

输出格式:
一个整数,表示方案数

输入输出样例
输入样例#1:
2
输出样例#1:
2
说明
必开QWORD

测试:N=15

回溯:1秒(超时)

模拟栈:大于10分钟

递归算法:1秒(超时)

动态规划:0 MS

组合算法:16 MS

题意:每个100元来之前必须有一个没走的50元,然后一起原地消失,让人想起了括号匹配
这道题目给出的方向已经很明确了(说明都给你测试了)
很显然,可行的操作只有动规和组合算法。
但是!不信邪的摸鱼酱用没有回溯的DFS跑了一遍感觉还行,20组数组超时了4组(17,18,19,20)
代码:

#include<bits/stdc++.h>
using namespace std;
int n,cnt;
void dfs(int a,int b,int step)
{
    if(b<a)return;
    if(a<0||b<0)return;
    if(step==2*n)
    {
        cnt++;
        return;
    }
    dfs(a-1,b,step+1);
    if(b>=a)dfs(a,b-1,step+1);
}
int main()
{
    cin>>n;
    dfs(n,n,0);
    cout<<cnt<<endl;
    return 0;
}

思路很清晰,来50的或者来100的,不符合情况直接return,代码也很简单。
但是终究是A不了啊!
倔强的摸鱼酱依然没有考虑给出的那两种可行方法
自学了卡特兰数立志用膜法打败膜法
用到了上面链接那篇博客的公式②,想了解的可以去看一下。
代码没想到比DFS还要简单...
DFS 21行,这个只有11行
极简代码:

#include<bits/stdc++.h>
using namespace std;
long long h[20+2]={1,1},n;
int main()
{
    cin>>n;
    for(int i=2;i<=n;i++)
        h[i]=h[i-1]*(4*i-2)/(i+1);
    cout<<h[n]<<endl;
    return 0;
}

ov.

猜你喜欢

转载自www.cnblogs.com/moyujiang/p/11234332.html