HDU 递推专题

1001: Buy the Ticket

Problem Description

The "Harry Potter and the Goblet of Fire" will be on show in the next few days. As a crazy fan of Harry Potter, you will go to the cinema and have the first sight, won’t you?

Suppose the cinema only has one ticket-office and the price for per-ticket is 50 dollars. The queue for buying the tickets is consisted of m + n persons (m persons each only has the 50-dollar bill and n persons each only has the 100-dollar bill).

Now the problem for you is to calculate the number of different ways of the queue that the buying process won't be stopped from the first person till the last person.

Note: initially the ticket-office has no money.

The buying process will be stopped on the occasion that the ticket-office has no 50-dollar bill but the first person of the queue only has the 100-dollar bill.

Input

The input file contains several test cases. Each test case is made up of two integer numbers: m and n. It is terminated by m = n = 0. Otherwise, m, n <=100.

Output

For each test case, first print the test number (counting from 1) in one line, then output the number of different ways in another line.

Sample Input

3 0

3 1

3 3

0 0

Sample Output

Test #1:

6

Test #2:

18

Test #3:

180

Source

HUANG, Ninghai

 

题目分析:

 

题目大意:

电影院买票,收银台没有零钱,而排队买票的人手里拿着的都是100元或是50元,每张票50元,给出拿100或50的各自人数,求出有几种排列方法使得收银台不会因找不出钱而停止!

 

我的思路:

设m张50元n张100元时的排列方法有f(m,n)种,总人数为m+n;当总人数为m+n-1时,有两种情况:

(1)m少1。此时必须要满足m>n(若m=n,则m-1< P>

(2)n少1。排列方法有f(m,n-1)种。当n-1多1时,同理有n*f(m,n-1)种方法。

由以上两种情况得到递推公式:

当m=n时,f(m,n)=n*f(m,n-1);

当m>n时,f(m,n)=m*f(m-1,n)+n*f(m,n-1);

当m<n时,f(m,n)=0.

下一步就要确定初始条件:

当m=1, n=0时,f(m,n)=1; 当m=1, n=1时,f(m,n)=1.

另外,由于本题的数据比较大,必须要用高精度,而且递归会超时,要用数组来保存数据。那么,选用哪种类型的数组比较好呢?很显然,本题涉及到很大的运算量,用整型的数组比较好。于是,用f[m][n][]代表f(m,n)。

 

以下是我的代码:

 

#include<stdio.h>

#define c 51                      //定义数组的长度

#define d 100000000        //定义常量,用于整型数组的数据处理

int main()

{

    int m,n,i,j,k,t=1,temp=0,f1,f2;

    __int64 ff;

    int f[101][101][c]={0};                         //数组初始化为0

    f[1][0][0]=1;                                          //初始条件

    f[1][1][0]=1;                                         //初始条件

    for(i=2;i<=100;i++)

      for(j=0;j<=i;j++)

        {

         for(k=0;k<c;k++)

           if(j==i)

           {

            ff=(__int64)j*f[i][j-1][k]+temp;   //注意,当数据比较大时,

            if((ff>d)&&(k<c-1))                    // j*f[i][j-1][k]会超出整型的范围,

            {                                                   //故用(__int64)强制类型转换

              temp=ff/d;                               

              ff%=d;

              f[i][j][k]=(int)ff;

            }

            else f[i][j][k]=(int)ff,temp=0;

           }

           else

           {

            ff=(__int64)i*f[i-1][j][k]+(__int64)j*f[i][j-1][k]+temp;

            if((ff>d)&&(k<c-1))

            {

              temp=ff/d;

              ff%=d;

              f[i][j][k]=(int)ff;

            }

            else f[i][j][k]=(int)ff,temp=0;

           }

         }

    while(scanf("%d%d",&m,&n)!=EOF&&((m!=0)||(n!=0)))

    {

       printf("Test #%d:\n",t++);

       for(i=c-1;i>0;i--)if(f[m][n][i]!=0)break;  //去掉数据中无效的0

       printf("%d",f[m][n][i]);

       for(j=i-1;j>=0;j--)printf("%08d",f[m][n][j]);        //%08d中08表示输出的数

       printf("\n");                                                           //据占8位,这是因为模

    }                                                                                 //100000000后,保存的数据

    return 0;                                                                      //只有8位

PS:此题用了个3维的数组,占用的空间比较大,可以考虑用两个2维的数组代替。另外,此题用C++提交会超时且堆栈溢出,而用G++提交则不会,这说明本代码不优,同时也间接说明了用G++提交代码的好处。

 

 

 

 

 

 

 

1002:Tri Tiling

Problem Description

In how many ways can you tile a 3xn rectangle with 2x1 dominoes? Here is a sample tiling of a 3x12 rectangle.

 

 Input

Input consists of several test cases followed by a line containing -1. Each test case is a line containing an integer 0 ≤ n ≤ 30.

Output

For each test case, output one integer number giving the number of possible tilings.

Sample Input

2

8

12

-1

Sample Output

3

153

2131

Source

University of Waterloo Local Contest 2005.09.24

 

题目分析:

 

题目大意:

用2*1大小的多米诺骨排盖3*n的矩形,问有多少种盖法。

 

我的思路:

首先可以看出,当n为奇数时,无论怎么盖也不会盖成3*n的矩形,故只需考虑n为偶数即可。可以将此题抽象为一个3*n的矩阵,用f(a,b,c)代表有多少种盖法,其中a,b,c分别代表第1、2、3行的元素个数,由此推导递归公式。假设第n列已盖好,那么它可由以下几种情况组成:

(1)    横放3个,此时f(a,b,c)=f(a-2,b-2,c-2);

(2)    竖放1个,横放1个,此时f(a,b,c)=f(a-1,b-1,c-2);

(3)    横放1个,竖放1个,此种情况与(2)对称,故仍可用f(a,b,c)=f(a-1,b-1,c-2)。

 

于是得递推公式:

当a=b=c时,f(a,b,c)= 2*f(a-2,b-1,c-1)+f(a-2,b-2,c-2);

当a<b且b=c时,f(a,b,c)= f(a,b-1,c-1)+f(a-2,b-2,c-2).

(由于f(a-2,b-1,c-1)产生了另一种情况:a<b且b=c,此时它由f(a,b-1,c-1)和f(a-2,b-2,c-2)两种情总组成。f(a,b-1,c-1)表示该情况是由第二第三排竖放一个产生的;f(a-2,b-2,c-2)表示该情况是由3个横放产生的,当然第一排的横放要比第二第三排缩一格。)

下一步就是要确定初始条件:

当a=b=c=0时,f(a,b,c)=1.因为一列也不排也算是一种方法。

当a或b或c中有一个小于0时,f(a,b,c)=0.因为这种情况不可能存在。 

以下是我的代码:

 

#include<stdio.h>

int f(int a,int b,int c)

{

    if(a*b*c==0)return 1;

    else if(a<0||b<0||c<0)return 0;

    else if(a==b&&b==c)return 2*f(a-2,b-1,c-1)+f(a-2,b-2,c-2);

    else if(a<b&&b==c)return f(a,b-1,c-1)+f(a-2,b-2,c-2);

}

int main()

{

    int n,s;

    while(scanf("%d",&n)!=EOF&&n!=-1)

    {

      if(n%2==0)s=f(n,n,n);

      else s=0;

      printf("%d\n",s);

    }

    return 0;

PS:此题也可以根据递推用数组解决,以减少题目用时。

 

 

 

 

 

 

1003:汉诺塔II

Problem Description

经典的汉诺塔问题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。Gardon就收到了一个汉诺塔玩具作为生日礼物。

  Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?

Input

包含多组数据,每个数据一行,是盘子的数目N(1<=N<=64)。

Output

对于每组数据,输出一个数,到达目标需要的最少的移动数。

Sample Input

1

3

12

Sample Output

1

5

81

Author

Gardon

Source

Gardon - DYGG's contest 2

 

题目分析:

 

我的思路:

刚开始没什么思路,于是分析数据,发现了下面的规律:

a[1]=1;

a[2]=a[1]+2;a[3]=a[2]+2;(2个加2^1)

a[4]=a[3]+4;a[5]=a[4]+4;a[6]=a[5]+4;(3个加2^2);

…………………………………………(4个加2^3);

……

 

以下是我的代码:

 

#include<stdio.h>

#include<math.h>

int main()

{

    int n,i,j,k,sum;

    int f;

    while(scanf("%d",&n)!=EOF)

    {

      k=2;

      for(i=1;i<=n;i++)

      {

        if(i==1)f=1,sum=1;

        else

        {

          for(j=k;sum<i;j++)sum+=j;

          k=j;

          f+=(int)pow(2,j-2);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值