DFS初步:递推,递归

8 篇文章 0 订阅

A - 一只小蜜蜂...

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

Input
输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50)。
Output
对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行。
Sample Input
2
1 2
3 6
Sample Output
1
3

解题思路:从图中可以看出,由1→3,可能的情况有两种:1→3或2→3。

即:若要到达X(X>=3),则上一步的状态为X-1或X-2。

由此得出递推公式:f[x]=f[x-1]+f[x-2].(x>=3)

代码:

#include<stdio.h>
long long c[60]={1,1};
void dg(int x)
{
    for(int i=2;i<x;i++)
        c[i]=c[i-1]+c[i-2];//递推
}//预处理
int main()
{
    int n;
    dg(50);
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%lld\n",c[b-a]);//解只取决于起点和终点之间的距离
    }
    return 0;
}

B - 不容易系列之(3)―― LELE的RPG难题

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

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

以上就是著名的RPG难题.

如果你是Cole,我想你一定会想尽办法帮助LELE解决这个问题的;如果不是,看在众多漂亮的痛不欲生的Cole女的面子上,你也不会袖手旁观吧?  
Input
输入数据包含多个测试实例,每个测试实例占一行,由一个整数N组成,(0<n<=50)。
Output
对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。
Sample Input
1
2
Sample Output

            3
            6

解题思路:题目要求有两个:相邻颜色不同,首尾颜色不同,设由长度为N的色块涂法为f[n]

开始递推,假设有长度为N(N>=4)的色块要涂,设首位为R,空出最后两个色块考虑

                 R........_ _

最后一个色块的涂法有两种情况。如果倒数第二块色块为R,则最后一块可以涂P或G,此时倒数第3块色块不可能是R,前N-2块色块的涂法满足f[n-2];如果倒数第二块色块不为R,则最后一块只能涂P或G其中1个,前N-1块涂法满足f[n-1]。

得出递推公式:f[n]=2*f[n-2]+f[n-1](n>=4)

代码:

#include<stdio.h>
long long c[60]={3,6,6};
int dg(int x)
{
    for(int i=3;i<x;i++)
        c[i]=c[i-1]+c[i-2]*2;//递推
    return 0;
}
int main()
{
    int n;
    dg(50);//预处理
    while(scanf("%d",&n)!=EOF)
    {
        printf("%lld\n",c[n-1]);
    }
    return 0;
}


C - 骨牌铺方格

在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数.
例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图:  

Input
输入数据由多行组成,每行包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0<n<=50)。
Output
对于每个测试实例,请输出铺放方案的总数,每个实例的输出占一行。
Sample Input
1
3
2
Sample Output
1
3
2

解题思路:设要铺设的长方形长度为n(n>=2),方法种数为f[n];

假设我们现在已经几乎铺完这个长方形,还有一步,就可以把长方形铺满,最后一步的情况有两种:

剩余2的长度,铺法:前面长度的铺法为f[n-2]

剩余1的长度,铺法:前面长度的铺法为f[n-1]

那么总共的铺法种数f[n]为这两种铺法种数只和,得到递推公式f[n]=f[n-2]+f[n-1].

代码:

#include<stdio.h>
long long c[60]={1,2,3};
int dg(int x)
{
    for(int i=3;i<x;i++)
        c[i]=c[i-1]+c[i-2];
    return 0;
}
int main()
{
    int n;
    dg(50);
    while(scanf("%d",&n)!=EOF)
    {
        printf("%lld\n",c[n-1]);
    }
    return 0;
}


D - 阿牛的EOF牛肉串

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

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

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

再次感谢!

Input
输入数据包含多个测试实例,每个测试实例占一行,由一个整数n组成,(0<n<40)。
Output
对于每个测试实例,请输出全部的满足要求的涂法,每个实例的输出占一行。
Sample Input
1
2
Sample Output
3
8

解题思路:设长度为n的刻法有f[n]中,第n个字母是o的种数为o[n],第n个字母不是n的种数为x[n].

从n=1开始递推:

                          x[1]=2;

                          o[1]=1;

                          f[n]=o[n]+x[n];

n=2:不论第一个字母是什么,第二个字母都可以刻E或F,所以x[2]=2*f[1].当前一个字母不是o时,第二个字母才能刻o,则o[2]=x[1].

由此得到递推规律:x[n]=2*f[n-1];

                                o[n]=x[n-1];

                                f[n]=o[n]+x[n];

代码:

#include<stdio.h>
long long c[60][2];//我用二维数组来储存x[n]和o[n]
int dg(int x)
{
    c[0][0]=2;
    c[0][1]=1;
    for(int i=1;i<x;i++)
    {
        c[i][0]=2*(c[i-1][0]+c[i-1][1]);
        c[i][1]=c[i-1][0];
    }
    return 0;
}
int main()
{
    int n;
    dg(50);
    while(scanf("%d",&n)!=EOF)
    {
        printf("%lld\n",c[n-1][0]+c[n-1][1]);
    }
    return 0;
}

E - 神、上帝以及老天爷

HDU 2006'10 ACM contest的颁奖晚会隆重开始了!
为了活跃气氛,组织者举行了一个别开生面、奖品丰厚的抽奖活动,这个活动的具体要求是这样的:

首先,所有参加晚会的人员都将一张写有自己名字的字条放入抽奖箱中;
然后,待所有字条加入完毕,每人从箱中取一个字条;
最后,如果取得的字条上写的就是自己的名字,那么“恭喜你,中奖了!”

大家可以想象一下当时的气氛之热烈,毕竟中奖者的奖品是大家梦寐以求的Twins签名照呀!不过,正如所有试图设计的喜剧往往以悲剧结尾,这次抽奖活动最后竟然没有一个人中奖!

我的神、上帝以及老天爷呀,怎么会这样呢?

不过,先不要激动,现在问题来了,你能计算一下发生这种情况的概率吗?

不会算?难道你也想以悲剧结尾?!

Input
输入数据的第一行是一个整数C,表示测试实例的个数,然后是C 行数据,每行包含一个整数n(1<n<=20),表示参加抽奖的人数。

Output
对于每个测试实例,请输出发生这种情况的百分比,每个实例的输出占一行, 结果保留两位小数(四舍五入),具体格式请参照sample output。

Sample Input
1
2
Sample Output
50.00%

递推过程:用A-1,B-2来代表是否抽到自己的名字,例:

A B C D E

1  2  3 4  5

此时n=5,考虑E,E没有拿到自己的名字,种数为n-1,此时(例举一种情况):

A B C D                E

1 2  3  5                 4    

若D拿到5, 则剩下的3个人拿错的种类为f[3];

若D不拿5,可以看做D拿到5是中奖的,剩下的4人排列类似于:

A B C D

1 2  3  4

拿错种数为f[4];

得到f[5]=(5-1)*(f[4]+f[3]);

递推公式f[n]=(n-1)*(f[n-1]+f[n-2]);

全部的排列为s[n]=n!;

概率为f[n]/s[n];

代码:

#include<stdio.h>
double s[30]={0,1,2},n[30]={0,0,1};
void gl(int x)
{
    for(int i=3;i<x;i++)
    {
        n[i]=(i-1)*(n[i-1]+n[i-2]);
        s[i]=s[i-1]*i;
    }
}
int main()
{
    int i,c;
    char x='%';
    gl(25);
    scanf("%d",&c);
    while(c--)
    {
        scanf("%d",&i);
        printf("%.2f%c\n",(n[i]/s[i])*100,x);
    }
    return 0;
}

F - 不容易系列之(4)――考新郎

国庆期间,省城HZ刚刚举行了一场盛大的集体婚礼,为了使婚礼进行的丰富一些,司仪临时想出了有一个有意思的节目,叫做"考新郎",具体的操作是这样的:


首先,给每位新娘打扮得几乎一模一样,并盖上大大的红盖头随机坐成一排;
然后,让各位新郎寻找自己的新娘.每人只准找一个,并且不允许多人找一个.
最后,揭开盖头,如果找错了对象就要当众跪搓衣板...

看来做新郎也不是容易的事情...

假设一共有N对新婚夫妇,其中有M个新郎找错了新娘,求发生这种情况一共有多少种可能.

Input
输入数据的第一行是一个整数C,表示测试实例的个数,然后是C行数据,每行包含两个整数N和M(1<M<=N<=20)。
Output
对于每个测试实例,请输出一共有多少种发生这种情况的可能,每个实例的输出占一行。
Sample Input
2
2 2
3 2
Sample Output
1
3

解题思路:错排递推如E,错排的种数乘上排列即可;

代码:

#include<stdio.h>
long long s[30]={1,1,2},w[30]={0,0,1};
void gl(int x)
{
    for(int i=3;i<x;i++)
    {
        w[i]=(i-1)*(w[i-1]+w[i-2]);
        s[i]=s[i-1]*i;
    }
}
int main()
{
    int n,m,c;
    gl(21);
    scanf("%d",&c);
    while(c--)
    {
        scanf("%d%d",&n,&m);
        printf("%lld\n",w[m]*(s[n]/(s[m]*s[n-m])));
    }
    return 0;
}


G - 折线分割平面


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

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

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

Sample Input
2
1
2
Sample Output
2
7

解题思路:先从直线分割平面开始递推。易得当画第i条线时,最多可与前面画的嫌产i-1个交点,产生(i-1)+1个面;

同理,当话第i条折线时,最多可以产生2*2*(i-1)个点,产生4*(i-1)+1个新面;

得到递推公式:f[i]=f[i-1]+4*(i-1)+1;

代码:

#include<stdio.h>
long long s[11000]={1,2,7};
void gl(int x)
{
    for(int i=3;i<x;i++)
    {
        s[i]=s[i-1]+4*(i-1)+1;
    }
}
int main()
{
    int n,c;
    gl(10050);
    scanf("%d",&c);
    while(c--)
    {
        scanf("%d",&n);
        printf("%lld\n",s[n]);
    }
    return 0;
}

H - 超级楼梯

                   
有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?
Input
输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
Output
对于每个测试实例,请输出不同走法的数量
Sample Input
2
2
3
Sample Output
1
2

递推过程:跨上第M介台阶的那一步有两种情况从M-2→M,从M-1→M。分别对应f[m-2]和f[m-1];

得到递推公式f[n]=f[n-1]+f[n-2];

代码:

#include<stdio.h>
int main()
{
    long long f[45]={0,0,1,2};
    int c,n;
    for(int i=4;i<45;i++)
        f[i]=f[i-1]+f[i-2];
    scanf("%d",&c);
    while(c--)
    {
        scanf("%d",&n);
        printf("%lld\n",f[n]);
    }
    return 0;
}


                         






                   


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值