hdoj Buy the Ticket

算法分析:
首先假设人无区别
令f(m,n)表示有m个人手持¥50的钞票,n个人手持¥100的钞票时共有的方案总数。则可以分以下情况讨论这个问题:
(1)当n=0时   n=0意味着排队购票的所有人手中拿的都是 ¥50的钞票,那么这m个人排队方案总数为1。
(2)当m<n时 显然,f(m,n)=0
(3)其他情况:

  考虑(m+n)个人排队购票的情景,第(m+n)人站在第(m+n-1)个人的后面,则第(m+n )个人的排队方式可以由下列两种情况获得:

  a.第(m+n )个人手持¥100的钞票,则在他之前的(m+(n-1))个人中有m个人手持¥50的钞票,有(n-1)个人手持¥100的钞票,此种情况共有f(m,n-1);

  b.第(m+n )个人手持¥50的钞票,则在他之前的((m-1)+n)个人中有m-1个人手持¥50的钞票,有n个人手持¥100的钞票,此种情况共有f(m-1,n)
根据加法原理得到:
f(m,n)=f(m-1,n)+f(m,n-1)
于是得到f(m,n)的计算公式

人是有区别的,对于持有100和50 钞票的人分别进行全排列即为最后要的结果。
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 100;

int dp[N+5][N+5][500];
int ans[10000];
void bigadd(int m, int n) {
    int i, len;
    len = max(dp[m][n-1][0], dp[m-1][n][0]);
    for (i = 1; i <= len; ++i)
        dp[m][n][i] = dp[m][n-1][i] + dp[m-1][n][i];
    for (i = 1; i <= len; ++i) {
        if (dp[m][n][i] > 9) {
            dp[m][n][i+1] += dp[m][n][i]/10;
            dp[m][n][i] %= 10;
        }
    }
    while (dp[m][n][i]) {
        dp[m][n][i+1] += dp[m][n][i]/10;
        dp[m][n][i] %= 10;
        i++;
    }
    dp[m][n][0] = i - 1;
}

void init() {
    int i, j;
    for (i = 0; i <= N; ++i)
        for (j = 0; j <= N; ++j) {
            dp[i][j][0] = 1;
            dp[i][j][1] = 0;
        }
    for (i = 0; i <=N; ++i)
        dp[i][0][0] = dp[i][0][1] = 1;
    for (i = 1; i <= N; ++i)
        for (j = 1; j <= i; ++j) {
            bigadd(i, j);
        }
}

void multiply(int m, int n, int c) {
    int i, len;
    while(c) {
        len = ans[0];
        for(i = 1; i <= len; ++i) {
            ans[i] *= c;
        }
        for(i = 1; i <= len; ++i) {
            if (ans[i] > 9) {
                ans[i+1] += ans[i]/10;
                ans[i] %= 10;
            }
        }
        while (ans[i]) {
            ans[i+1] += ans[i]/10;
            ans[i] %= 10;
            i++;
        }
        ans[0] = i-1;
        c--;
    }
}

int main()
{
    init();
    int m, n, ca = 0;
    while (scanf("%d %d", &m, &n) != EOF && (n!=0 || m!=0)) {
        printf("Test #%d:\n", ++ca);
        memcpy(ans, dp[m][n], sizeof(ans));
        multiply(m, n, m);
        multiply(m, n, n);
        int i;
        for (i = ans[0]; i >= 1; --i)
            printf("%d", ans[i]);
        printf("\n");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值