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

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

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

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

 

以下是我的代码:

 

#include

#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

           if(j==i)

           {

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

            if((ff>d)&&(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

            {

              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

(由于f(a-2,b-1,c-1)产生了另一种情况:a

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

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

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

以下是我的代码:

 

#include

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

}

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

#include

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

          k=j;

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

        }

      }

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

    }

    return 0;

 

 

 

 

 

 

1004:三角形

Problem Description

用N个三角形最多可以把平面分成几个区域?

Input

输入数据的第一行是一个正整数T(1<=T<=10000),表示测试数据的数量.然后是T组测试数据,每组测试数据只包含一个正整数N(1<=N<=10000).

Output

对于每组测试数据,请输出题目中要求的结果.

Sample Input

2

1

2

Sample Output

2

8

Author

Ignatius.L

 

题目分析:

 

我的思路:

第n个三角形每条边最多与2*(n-1)条边相交。对于每条边,它所截出的区域(不算第n个三角形的角)有2*(n-1)-1个,于是3条边可截出6*(n-1)-3个区域,再加上3个角即可多出6*(n-1)个区域。

于是得递推公式:f(n)=f(n-1)+ 6*(n-1)

初始条件是:f(1)=2

 

以下是我的代码:

 

#include

int main()

{

       int t,n;

       __int64 f;

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

       while(t--)

       {

              scanf("%d",&n);

              f=2;

              while(n!=1)f+=6*(n-1),n--;

              printf("%I64d\n",f);

       }

       return 0;

PS:由以上递推公式可得到最终公式,使得代码更加优化,这里就不再细说了。

另外,平面是2维的,它跟二次多项式a*x^2+b*x+c有关,我们可以用1、2、3个平面的情况推出系数a,b,c,这样同样可以得到最终公式!

 

 

 

 

 

 

1005:下沙的沙子有几粒?

Problem Description

2005年11月份,我们学校参加了ACM/ICPC 亚洲赛区成都站的比赛,在这里,我们获得了历史性的突破,尽管只是一枚铜牌,但获奖那一刻的激动,也许将永远铭刻在我们几个人的心头。借此机会,特向去年为参加ACM亚洲赛而艰苦集训了近半年的各位老队员表示感谢。

实际上,除了获奖以外,在这次比赛期间还有一件事也让我们记忆深刻。那是比赛当天等待入场的时候,听到某个学校的一个队员在说:“有个学校的英文名很有意思,叫什么Hangzhou Dianzi University”. 哈哈,看来我们学校的英文名起的非常好,非常吸引人呀。

不过,事情的发展谁也没有料到,随着杭电英文校名的这一次曝光,影响越来越大,很多人开始对杭电英文校名进行研究,不久以后甚至还成立了一个专门的研究机构,叫做“HDU 校名研究会”。并不断有报道说-相-当-多的知名科学家改行,专门对该问题进行研究,学术界称之为“杭电现象”。很多人在国际知名期刊上发表了研究论文,这其中,尤以中国超级女科学家宇春小姐写的一篇研究报告最为著名,报告发表在science上,标题是“杭电为什么这样红?” 文中研究发现:Hangzhou Dianzi University这个校名具有深刻的哲学思想和内涵,她同时提出了一个大胆的猜想:“假定一个字符串由m个H和n个D组成,从左到右扫描该串,如果字符H的累计数总是不小于字符D的累计数,那么,满足条件的字符串总数就恰好和下沙的沙粒一样多。”

这就是当今著名的“宇春猜想”!

虽然还没能从数学上证明这个猜想的正确性,但据说美国方面在小布什的亲自干预下,已经用超级计算机验证了在(1<=n<=m<=1000000000000)时都是正确的。my god! 这是一个多么伟大的猜想!虽然我们以前总说,21世纪是属于中国的,可还是没想这一天来的这么早,自豪ing... + 感动ing...

感动和自豪之余,问题也来了,如果已知m和n的值,请计算下沙的沙粒到底有多少。

Ps:

1. 中国有关方面正在积极行动,着手为宇春小姐申报诺贝尔奖。

2、“宇春猜想”中提到的H和D组成的字符串现在被学术界成为“杭电串串”(“杭电串串”前不久被一个卖羊肉串的注册了商标,现在我校正在积极联系买断,据说卖方的底价是1000万欧元,绝不打折,看来希望不大,sigh...)

Input

输入数据包含多个测试实例,每个占一行,由两个整数m和n组成,m和 n 分别表示字符串中H和D的个数。由于我们目前所使用的微机和老美的超级计算机没法比,所以题目给定的数据范围是(1<=n<=m<=20)。

Output

对于每个测试实例,请输出下沙的沙粒到底有多少,计算规则请参考“宇春猜想”,每个实例的输出占一行。

Sample Input

1 1

3 1

Sample Output

1

3

Author

lcy

Source

HDU 2006-4 Programming Contest

 

题目分析:

 

 

我的思路:

设由m个H和n个D组成的串有f(m,n)个,它是由m+n-1个再加上一个H或D组成的。

于是得递推公式:

f(m,n)=f(m-1,n)+f(m,n-1);

下一步确定初始条件:

f(0,1)=0; f(1,0)=1.

另外,当m

以下是我的代码:

 

#include

int main()

{

    int n,m,i,j;

    __int64 f[22][22];

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

    {

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

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

        {

          if((i==0)||(i

          else if(j==0)f[i][j]=1;

          else f[i][j]=f[i-1][j]+f[i][j-1];

        }

       printf("%I64d\n",f[m][n]);

    }

    return 0;

PS:本题与1001类似,但不同的是,1001中拿50块钱的人是不同的,所以交换位置也是一种排法;而本题中m个H是相同的,所以加进的H无需与前m-1个H交换位置。另外,本题数据量比较小,因此更加简单!

 

 

 

 

 

 

1006:钱币兑换问题

Problem Description

在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很多种兑法。请你编程序计算出共有多少种兑法。

Input

每行只有一个正整数N,N小于32768。

Output

对应每个输入,输出兑换方法数。

Sample Input

2934

12553

Sample Output

718831

13137761

Author

SmallBeer(CML)

Source

杭电ACM集训队训练赛(VII)

 

 

题目分析:

 

我的思路:

假设数N/3得到的商为S,则可以分成S+1种大情况(即0~S个3)讨论,对于每种大情况i (0<=i<=S),设(N-i*3)/2=W, 则又可以分为W+1种小情况(即0~W个2),而每个小情况中2的个数X则为X种兑法,因为3和2确定后,1也确定了,此时即为一种兑法。

 

我的代码如下:

 

#include

int main()

{

    int i,j,n,tempi,tempj;

    __int64 f;

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

    {

      tempi=n/3;

      f=0;

      for(i=0;i<=tempi;i++)f+=(n-i*3)/2+1;

      printf("%I64d\n",f);

    }

    return 0;

 

 

 

1007:献给杭电五十周年校庆的礼物

Problem Description

或许你曾经牢骚满腹

或许你依然心怀忧伤

或许你近在咫尺

或许你我天各一方

对于每一个学子

母校

永远航行在

生命的海洋

今年是我们杭电建校五十周年,这是一个值得祝福的日子。我们该送给母校一个怎样的礼物呢?对于目前的大家来说,最好的礼物当然是省赛中的好成绩,我不能参赛,就送给学校一个DOOM III球形大蛋糕吧,这可是名牌,估计要花掉我半年的银子呢。

想象着正式校庆那一天,校长亲自操刀,把这个大蛋糕分给各地赶来祝贺的校友们,大家一定很高兴,呵呵,流口水了吧...

等一等,吃蛋糕之前先考大家一个问题:如果校长大人在蛋糕上切了N刀(校长刀法极好,每一刀都是一个绝对的平面),最多可以把这个球形蛋糕切成几块呢?

做不出这个题目,没有蛋糕吃的!

为-了-母-校-,为-了-蛋-糕-(不是为了DGMM,枫之羽最会浮想联翩...),加-油-!

Input

输入数据包含多个测试实例,每个实例占一行,每行包含一个整数n(1<=n<=1000),表示切的刀数。

Output

对于每组输入数据,请输出对应的蛋糕块数,每个测试实例输出一行。

Sample Input

1

2

3

Sample Output

2

4

8

Author

lcy

Source

杭电ACM集训队训练赛(VIII)

 

 

题目分析:

 

我的思路:

这其实是考我们n个平面最多可以把空间分成几个部分的问题。

使第n个平面与前面n-1个平面都相交,且交线都不重合,那么n-1条直线最多可以把平面划分成为n(n-1)/2+1个部分

于是得递推公式f(n)=f(n-1)+n(n-1)/2

初始条件:f(1)=2

 最后可以推出公式:f(n)=(n^3+5n+6)/6

 

我的代码如下:

 

#include

int main()

{

    int n;

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

      printf("%d\n",(n*n*n+5*n+6)/6);

    return 0;

PS:空间是3维的,它跟三次多项式a*x^3+b*x^2+c*x+d有关,我们可以由4种特殊情况(例如x=1、2、3、4)列四个方程,解出系数a,b,c,d,从而求出最终公式!

 

 

 

 

 

 

1008:Children’s Queue

Problem Description

There are many students in PHT School. One day, the headmaster whose name is PigHeader wanted all students stand in a line. He prescribed that girl can not be in single. In other words, either no girl in the queue or more than one girl stands side by side. The case n=4 (n is the number of children) is like

FFFF, FFFM, MFFF, FFMM, MFFM, MMFF, MMMM

Here F stands for a girl and M stands for a boy. The total number of queue satisfied the headmaster’s needs is 7. Can you make a program to find the total number of queue with n children?

Input

There are multiple cases in this problem and ended by the EOF. In each case, there is only one integer n means the number of children (1<=n<=1000)

Output

For each test case, there is only one integer means the number of queue satisfied the headmaster’s needs.

Sample Input

1

2

3

Sample Output

1

2

4

Author

SmallBeer (CML)

Source

杭电ACM集训队训练赛(VIII)

 

题目分析:

 

题目大意:

一个队伍中有n个学生,但规定女生不能单独站,也就是说,要么队伍中没有女生,要么有两个或两个以上的女生站在一起(这是保护弱势力的体现!)。问有多少这样的队伍。

 

我的思路:

设n个学生生按规则排成的队列有f(n)种,那么当总人数少一个时会是什么情况呢?显然,要么少一个男的,要么少一个女的。故有如下情况:

(1)    少一个男的,也就是说,第n个加进去的是男生。此时,队列n-1只需按规则站好即可,故有f(n-1)种方法。

(2)    少一个女的,也就是说,第n个加进去的是女生。此时,前面的肯定不能是男生,因为后面加进去的女生只有一个,不符合规则,因此第n-1个(也就是前1个)必须是女生。若n-2个是按规则站好的,则有f(n-2)种方法;若n-2个不是按规则站好的(因为第n-1,第n个是女生,所以第n-2个可以是女生,第n-3个可以是男生。当没加进第n-1和第n个女生的时候,这是不合规则的),即第n-2个是女生,第n-3个是男生,此后第n-4个必须按规则站好,故有f(n-4)种方法。

于是得递推公式:

f(n)=f(n-1)+f(n-2)+f(n-4);

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

由于递推公式有f(n-1)、f(n-2)和f(n-4),故必须给出f(1)、f(2) 、f(3)和 f(4)

由题意得:f(1)=1;f(2) =2;f(3)=4; f(4)=7。

 

注意:由于本题数据量比较大,必须要用高精度,同时用数组保存结果来代替递归。

下面是我的代码:

 

#include

#define c 31

#define d 100000000

int main()

{

    int n,i,j;

    int f[1000][c]={0};

    f[0][0]=1;

    f[1][0]=2;

    f[2][0]=4;

    f[3][0]=7;

    for(i=4;i<1000;i++)

    {

      for(j=0;j

        f[i][j]=f[i-1][j]+f[i-2][j]+f[i-4][j];

      for(j=0;j

        if(f[i][j]>d)

        {

          f[i][j+1]+=f[i][j]/d;

          f[i][j]%=d;

        }

    }

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

    {

      for(i=c-1;i>0;i--)if(f[n-1][i]!=0)break;

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

      for(j=i-1;j>=0;j--)printf("%08d",f[n-1][j]);

      printf("\n");

    }

    return 0;

 

 

 

 

 

 

1009:Counting Triangles

Problem Description

Given an equilateral triangle with n the length of its side, program to count how many triangles in it.

 

Input

The length n (n <= 500) of the equilateral triangle's side, one per line.

process to the end of the file

Output

The number of triangles in the equilateral triangle, one per line.

Sample Input

1

2

3

Sample Output

1

5

13

Author

JIANG, Jiefeng

Source

ZOJ Monthly, June 2003

 

 

题目分析:

 

题目大意:

边长为n的等边三角形由若干个边长为1的等边三角形组成,问它里面包含多少个等边三角形(边长从1到n,且有正立和倒立两种情况)。

 

我的思路:

先分析几个边长小的等边三角形的情况,借此得出递推公式。

由于边长>1的倒三角形比较难算,故分开讨论

边长                    正三角形                   边长为1的倒三角          边长>1的倒三角形

1                          h(1)=1                        g(1)=0                                      0

2                          h(2)=h(1)+3                g(2)=g(1)+1                              0

3                          h(3)=h(2)+6                g(3)=g(2)+2                              0

……

n                   h(n)=h(n-1)+ n*(n+1)/2     g(n)=g(n-1)+n-1                       ?

 

现在讨论边长>1的倒三角形数:

显然当边长>=4时才有边长>1的倒三角形。

边长      底边等分点数                  边长为i(i>1)的倒三角形数量

4            4-1                                     u(4)=(4-1)-2*(2-1)

5            5-1                                     u(5)=u(4)+ (5-1)-2*(2-1)+ (5-1)-2*(3-1)

6            6-1                                     u(6)=u(5)+ [(6-1)-2*(2-1)]+ [(6-1)-2*(3-1)]

……

n            n-1         u(n)=u(n-1)+[(n-1)-2*(2-1)]+[(n-1)-2*(3-1)]+…+[(n-1)-2*(i-1)]+…

 

于是得递推关系:

当n<4时,f(n)=f(n-1)+n*(n+1)/2+(n-1);

当n>=4时,f(n)=f(n-1)+n*(n+1)/2+(n-1)+u(n);

初始条件为: f(1)=1;

 

以下是我的代码:

 

#include

int main()

{

       int n,i,j;

       __int64 f;

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

       {

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

              if(i==1)f=1;

              else

              {

                f+=i*(i+1)/2+(i-1);        //加上正立三角形数和边长为1的倒三角形数

                if(i>=4)

                  for(j=3;i-j>=1;j+=2)f+=i-j;      //当n>=4时,加上边长>1的倒三角形数

                }

         printf("%I64d\n",f);

       }

       return 0;

 

 

 

 

 

1010:Tiling a Grid With Dominoes

Problem Description

We wish to tile a grid 4 units high and N units long with rectangles (dominoes) 2 units by one unit (in either orientation). For example, the figure shows the five different ways that a grid 4 units high and 2 units wide may be tiled.

Write a program that takes as input the width, W, of the grid and outputs the number of different ways to tile a 4-by-W grid.

Input

The first line of input contains a single integer N, (1 ≤ N ≤ 1000) which is the number of datasets that follow.

Each dataset contains a single decimal integer, the width, W, of the grid for this problem instance.

Output

For each problem instance, there is one line of output: The problem instance number as a decimal integer (start counting at one), a single space and the number of tilings of a 4-by-W grid. The values of W will be chosen so the count will fit in a 32-bit integer.

Sample Input

3

2

3

7

Sample Output

1 5

2 11

3 781

Source

2008 "Shun Yu Cup" Zhejiang Collegiate Programming Contest - Warm Up(1)

 

 

题目分析:

 

题目大意:

用1×2的多米诺骨牌,拼成4×w的矩形,总共有多少种方法?

 

我的思路:

此题与1002类似,但此题比1002复杂得多,用递归己经不能解决问题了,但可以借鉴它的思想,再转用数组存储即可。先说一下它的思想:

设f(a,b,c,d)表示第一行覆盖a格,第二行覆盖b格,第三行覆盖c格,第四行覆盖d格时的方法数,当拼成4*w的矩形时,有f(w,w,w,w)种方法。那么在此之前,它有哪些状态呢?由于骨排要么是横放要么是竖放,所以在取走第w列时,有下面几种情况:(a=b=c=d=w)

(1)f(a-1,b-1,c-2,d-2);//第一行第二行是竖放的,另外两行是横放的,其他情况类似

(2)f(a-2,b-2,c-1,d-1);

(3)f(a-2,b-1,c-1,d-2);

(4)f(a-2,b-2,c-2,d-2);

(5)f(a-1,b-1,c-1,d-1);

现在又要考虑上面的情况又是怎么得来的:

对于(1),它是由f(a-2,b-2,c,d)和f(a-1,b-1,c,d)得来的;

对于(2),它是由f(a,b,c-1,d-1)和f(a,b,c-2,d-2)得来的;

对于(3),它是由f(a,b-2,c-2,d)和f(a,b-1,c-1,d)得来的;

对于(4)和(5),它跟a=b=c=d的情况一样;

另外,还有一种情况:当a=d且b=c且a>b时,它是由f(a-2,b,c,d-2)得来的。

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

当a=b=c=d<0时,f(a,b,c,d)=0;

当a=b=c=d=0或者1时,f(a,b,c,d)=1;

当a=b=0且c=d=1或者a=b=1且c=d=0时,f(a,b,c,d)=1;

当a=d=0且b=c=1时,f(a,b,c,d)=1;

当a=d=1且b=c=1时,f(a,b,c,d)=0;

刚才已经说过,用递归会超时,所以要转成数组来存储,下面是数组的转化:

以1表示己经覆盖,0表示未覆盖,故每列均可由一个二进制数表示,情况如下:

f[t][0]:0000

f[t][1]:0011

f[t][2]:0110

f[t][3]:1001

f[t][4]:1100

f[t][5]:1111

初始条件和状态转换均可参考上面的思想。

 

 

以下是我的代码:

 

#include

#define c 25

int main()

{

    int n,w,t;

    int f[c+1][7];

    f[1][0]=f[1][1]=f[1][2]=f[1][4]=f[1][5]=1;

    f[1][3]=0;

    for(t=2;t<=c;t++)

    {

     f[t][0]=f[t-1][5];

     f[t][1]=f[t-1][5]+f[t-1][4];

     f[t][2]=f[t-1][5]+f[t-1][3];

     f[t][3]=f[t-1][2];

     f[t][4]=f[t-1][5]+f[t-1][1];

     f[t][5]=f[t-1][0]+f[t-1][1]+f[t-1][2]+f[t-1][4]+f[t-1][5];    

     }

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

    {

      int i=1;

      while(n--)

      {

        scanf("%d",&w);

        printf("%d %d\n",i++,f[w][5]);

      }

    }

    return 0;

 

 

 

由于时间有限,只分析以上10道题,以下10道题粘代码

 

1011:汉诺塔V

Problem Description

用1,2,...,n表示n个盘子,称为1号盘,2号盘,...。号数大盘子就大。经典的汉诺塔问

题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于

印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小

顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱

子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。我们

知道最少需要移动2^64-1次.在移动过程中发现,有的圆盘移动次数多,有的少 。 告之盘

子总数和盘号,计算该盘子的移动次数.

Input

包含多组数据,首先输入T,表示有T组数据.每个数据一行,是盘子的数目N(1<=N<=60)和盘

号k(1<=k<=N)。

Output

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

Sample Input

2

60 1

3 1

Sample Output

576460752303423488

4

 

Author

Zhousc@ECJTU

Source

ECJTU 2008 Spring Contest

 

我的代码如下:

 

#include

#include

int main()

{

    int t,n,k;

    __int64 f;

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

    while(t--)

    {

       scanf("%d%d",&n,&k);

       f=(__int64)pow(2,n-k);

       printf("%I64d\n",f);

    }

    return 0;

 

1012:汉诺塔VI

Problem Description

n个盘子的汉诺塔问题的最少移动次数是2^n-1,即在移动过程中会产生2^n个系列。由于

发生错移产生的系列就增加了,这种错误是放错了柱子,并不会把大盘放到小盘上,即各柱

子从下往上的大小仍保持如下关系 :

n=m+p+q

a1>a2>...>am

b1>b2>...>bp

c1>c2>...>cq

计算所有会产生的系列总数.

Input

包含多组数据,首先输入T,表示有T组数据.每个数据一行,是盘子的数

目N<30.

Output

对于每组数据,输出移动过程中所有会产生的系列总数。

Sample Input

3

1

3

29

Sample Output

3

27

68630377364883

Author

Zhousc@ECJTU

Source

ECJTU 2008 Spring Contest

 

 

以下是我的代码:

 

#include

#include

int main()

{

    double f;

    int t,n;

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

    while(t--)

    {

      scanf("%d",&n);

      f=pow(3,n);

      printf("%.0lf\n",f);

    }

    return 0;

 

1013:蟠桃记

Problem Description

喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事,你们一定都觉得这猴子太闹腾了,其实你们是有所不知:悟空是在研究一个数学问题!

什么问题?他研究的问题是蟠桃一共有多少个!

不过,到最后,他还是没能解决这个难题,呵呵^-^

当时的情况是这样的:

第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。聪明的你,请帮悟空算一下,他第一天开始吃的时候桃子一共有多少个呢?

Input

输入数据有多组,每组占一行,包含一个正整数n(1<30>

Output

对于每组输入数据,输出第一天开始吃的时候桃子的总数,每个测试实例占一行。

Sample Input

2

4

Sample Output

4

22

Author

lcy

Source

C语言程序设计练习(二)

 

 

#include

int main()

{

       int f,n;

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

       {

              f=1;

              while(n!=1)f=2*(f+1),n--;

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

       }

       return 0;

 

1014:超级楼梯

Problem Description

有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?

Input

输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。

Output

对于每个测试实例,请输出不同走法的数量

Sample Input

2

2

3

Sample Output

1

2

Author

lcy

Source

2005实验班短学期考试

 

以下是我的代码:

 

#include

int main()

{

       int s[41],n,m,i;

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

       while(n--)

       {

              scanf("%d",&m);

              for(i=0;i

              {

               if((i==0)||(i==1))s[i]=1;

             else if(i>1)s[i]=s[i-1]+s[i-2];

              }

              printf("%d\n",s[m-1]);

       }

       return 0;

 

 

1015:一只小蜜蜂...

Problem Description

有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行。请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数。

其中,蜂房的结构如下所示。

Input

输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<50>

Output

对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。

Sample Input

2

1 2

3 6

Sample Output

1

3

Author

lcy

Source

递推求解专题练习(For Beginner)

 

以下是我的代码:

 

#include

int main()

{

       int s[41],n,m,i;

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

       while(n--)

       {

              scanf("%d",&m);

              for(i=0;i

              {

               if((i==0)||(i==1))s[i]=1;

             else if(i>1)s[i]=s[i-1]+s[i-2];

              }

              printf("%d\n",s[m-1]);

       }

       return 0;

 

 

 

1016:不容易系列之(3)—— LELE的RPG难题

Problem Description

人称“AC女之杀手”的超级偶像LELE最近忽然玩起了深沉,这可急坏了众多“Cole”(LELE的粉丝,即"可乐"),经过多方打探,某资深Cole终于知道了原因,原来,LELE最近研究起了著名的RPG难题:

有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法.

以上就是著名的RPG难题.

如果你是Cole,我想你一定会想尽办法帮助LELE解决这个问题的;如果不是,看在众多漂亮的痛不欲生的Cole女的面子上,你也不会袖手旁观吧?

Input

输入数据包含多个测试实例,每个测试实例占一行,由一个整数N组成,(0<=50)。< P>

Output

对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。

Sample Input

1

2

Sample Output

3

6

Author

lcy

Source

递推求解专题练习(For Beginner)

 

 

以下是我的代码:

 

#include

int main()

{

    int n,i;

    __int64 f[51];

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

    {

      for(i=0;i

        if(i==0)f[i]=3;

        else if((i==1)||(i==2))f[i]=6;

        else f[i]=f[i-1]+2*f[i-2];

      printf("%I64d\n",f[n-1]);

    }

    return 0;

 

 

 

1017:阿牛的EOF牛肉串

Problem Description

今年的ACM暑期集训队一共有18人,分为6支队伍。其中有一个叫做EOF的队伍,由04级的阿牛、XC以及05级的COY组成。在共同的集训生活中,大家建立了深厚的友谊,阿牛准备做点什么来纪念这段激情燃烧的岁月,想了一想,阿牛从家里拿来了一块上等的牛肉干,准备在上面刻下一个长度为n的只由"E" "O" "F"三种字符组成的字符串(可以只有其中一种或两种字符,但绝对不能有其他字符),阿牛同时禁止在串中出现O相邻的情况,他认为,"OO"看起来就像发怒的眼睛,效果不好。

你,NEW ACMer,EOF的崇拜者,能帮阿牛算一下一共有多少种满足要求的不同的字符串吗?

PS: 阿牛还有一个小秘密,就是准备把这个刻有 EOF的牛肉干,作为神秘礼物献给杭电五十周年校庆,可以想象,当校长接过这块牛肉干的时候该有多高兴!这里,请允许我代表杭电的ACMer向阿牛表示感谢!

再次感谢!

Input

输入数据包含多个测试实例,每个测试实例占一行,由一个整数n组成,(0<40>

Output

对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。

Sample Input

1

2

Sample Output

3

8

Author

lcy

Source

递推求解专题练习(For Beginner)

 

以下是我的代码:

 

#include

int main()

{

    int n,i;

    __int64 f[41];

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

    {

      for(i=0;i

       if(i==0)f[i]=3;

       else if(i==1)f[i]=8;

       else f[i]=2*(f[i-1]+f[i-2]);

      printf("%I64d\n",f[n-1]);

    }

    return 0;

 

 

 

1018:折线分割平面

Problem Description

我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目。比如,一条折线可以将平面分成两部分,两条折线最多可以将平面分成7部分,具体如下所示。

Input

输入数据的第一行是一个整数C,表示测试实例的个数,然后是C 行数据,每行包含一个整数n(0<=10000),表示折线的数量。< P>

Output

对于每个测试实例,请输出平面的最大分割数,每个实例的输出占一行。

Sample Input

2

1

2

Sample Output

2

7

Author

lcy

Source

递推求解专题练习(For Beginner)

 

 

以下是我的代码:

 

#include

int main()

{

    int c,n,i;

    __int64 f;

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

    while(c--)

    {

      scanf("%d",&n);

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

        if(i==1)f=2;

        else f+=4*i-3;

      printf("%I64d\n",f);

    }

    return 0;

 

 

1019:汉诺塔III

Problem Description

约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。

现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。

Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?

Input

包含多组数据,每次输入一个N值(1<=N=35)。

Output

对于每组数据,输出移动最小的次数。

Sample Input

1

3

12

Sample Output

2

26

531440

Author

Rabbit

Source

RPG专场练习赛

 

以下是我的代码:

 

#include

int main()

{

    __int64 f[36];

    int n,i;

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

    {

        if(n==1)f[n]=2;

        else for(i=2;i<=n;i++)f[i]=3*f[i-1]+2;

        printf("%I64d\n",f[n]);

    }

    return 0;

 

 

1020:跳舞毯

Problem Description

由于长期缺乏运动,小黑发现自己的身材臃肿了许多,于是他想健身,更准确地说是减肥。

小黑买来一块圆形的毯子,把它们分成三等分,分别标上A,B,C,称之为“跳舞毯”,他的运动方式是每次都从A开始跳,每次都可以任意跳到其他块,但最后必须跳回A,且不能原地跳.为达到减肥效果,小黑每天都会坚持跳n次,有天他突然想知道当他跳n次时共几种跳法,结果想了好几天没想出来-_-

现在就请你帮帮他,算出总共有多少跳法。

Input

测试输入包含若干测试用例。每个测试用例占一行,表示n的值(1<=n<=1000)。

当n为0时输入结束。

Output

每个测试用例的输出占一行,由于跳法非常多,输出其对10000取模的结果.

Sample Input

2

3

4

0

Sample Output

2

2

6

Author

葱头

Source

2008信息工程学院集训队——选拔赛

 

 

以下是我的代码:

 

#include

int main()

{

    int n,i;

    __int64 f[1001];

    __int64 g[1001];

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

    {

      for(i=0;i

       if(i==0)f[i]=0,g[i]=1;

       else if(i==1)f[i]=2,g[i]=1;

       else

       {

         f[i]=2*g[i-1]%10000;

         g[i]=(f[i-1]+g[i-1])%10000;

         }

      printf("%I64d\n",f[n-1]);

    }

    return 0;

你可能感兴趣的:(ACM)