Chinaunix首页 | 论坛 | 博客
  • 博客访问: 57020
  • 博文数量: 7
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 80
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-26 22:26
文章分类
文章存档

2009年(2)

2008年(5)

我的朋友

分类: C/C++

2008-09-27 00:54:19

题意是给定一个从字母到数字的映射关系:a--1, b--2, ..., z--26.

则可以将一串字母表示成数字,如abc表示成123 xyz表示成242526.

 

但是这样的表示方法存在一个问题,就是同一个数字表示可能对应不同 的字母表示,比如242526可以翻译成xyz,也可以翻译成bdbebf

 

题目的输入是一串数字,要求的输出是一个整数,该整数表示的是有多少种不同的字母串可以按照上述规则被翻译,换句话说,就是有多少种不同的翻译方法。(只要求出可能的不同字符串的个数,不需要求出具体的字符串)。

 

Sample Input

25114
1111111111
3333333333
0

 

Sample Output

6
89
1

 

【分析】

对于一个给定的数字串,我们要想按照上述规则进行翻译,可以一次取一个数字翻译成一个字母,但有时也可以一次取2个数字翻译成一个字母。

 

例子一:以输入范例25114为例,假如我们现在扫描到第一个数字2,对于它,我们有2钟不同的翻译方法:一种是将2替换成b,然后继续翻译5114;另一种是将25替换成y,然后继续翻译114.如果继续翻译5114共有m种翻译方法,继续翻译114n种翻译方法,则串25114共有m+n种翻译方法。

 

例子二:再看一个例子,假如存在数字序列35114,仍然假设我们扫描到第一个数字3,此时由于35不可能翻译成一个字母,所以我们只有一种翻译方法,就是将3翻译成c。这样,35114共有多少种翻译方法取决于5114共有多少种翻译方法。

通过前面的两个例子的分析可以看出,问题的解是递归的。可以用下面的递归式表示:(其中input是输入的数字串,采用string存储)

 

对例子一:

method_cnt (input, n)  = method_cnt (input, n+1) + method_cnt (input, n+2)

 

对例子二:

 method_cnt (input, n) = method_cnt (input, n+1)

 

终止条件是什么呢?我们一直往下想,当上述翻译翻译到最后一个数字时,就会停止翻译,而最后一个数字的翻译方式只有一种,这样就有了终止条件。

 

而例子一和例子二的判断条件很简单,可以采用下面的方法实现:

 

int value = (input [n] – ‘0’) * 10 + (input [n+1] – ‘0’); //获得前两位转换成整数

if (value <=26)  //判断是哪一种情况(注意,这个判断条件有个问题!后面再说

{例子一情况}

else

{例子二情况}

 

看来我们已经可以开始动手了。下面是按照上面的分析写的代码:

 

#include

#include

using namespace std;

int Calc (string &input, int pos)

{

        if (pos >=str.size()-1 )

        {

            table[pos] = 1;

            return 1;   

        }

        int tmp = (input[pos] - '0') * 10 + (input[pos+1] - '0');

        if (tmp<=26)

        {

            int res = Calc (input, pos+1) + Calc (input, pos+2);

            return res;

        }

        else

        {

            int res = Calc (input, pos+1);

            return res;

        }

}

int main()

{

    string str;

    while (cin>>str, str!="0")

    {

        cout<

    }

     return 0;

}

 

看上去似乎是正确的,但是其实问题很多,不信你可以提交一下,保证WA

 

但是有一点可以肯定,我们的想法没错,也就是说递归式是正确的。我们一定是漏掉一些条件没考虑。

 

看一个输入实例:1020 

 

我们应该怎么翻译?按照上面的程序,会把0也当成可以翻译成一个字母的!显然是错的!我们忘记了处理0

 

事实上上例只能有一种翻译方式,就是1020这两个字母。我们要在递归调用之前就把0的情况排除。所以我们要修改上面 Calc函数:

 

int Calc (string &input, int pos)

{

        if (pos >=str.size()-1 )

        {

            return 1;   

        }

        if (input[pos] == 0)

{

    return 0; //让其返回0,即没有办法(有0种办法)翻译以0 打头的。

}

        int tmp = (input[pos] - '0') * 10 + (input[pos+1] - '0');

        if (tmp<=26)

        {

            int res = Calc (input, pos+1) + Calc (input, pos+2);

            return res;

        }

        else

        {

            int res = Calc (input, pos+1);

            return res;

        }

}

 

现在总算可以放心了。但是提交后发现还是会超时(Time Limit Exceed)。

不过这种情况自然会想到动态规划。打一张表就可以了。

具体思路是:把求到过的结果存储起来,下次再要求的时候直接返回结果,而不需要再求解一次。

 

这样源代码会变为如下:

 

#include

#include

#include

using namespace std;

 

vector <int> table; //用来存储计算结果的表

 

int Calc (string &input, int pos)

{

    if (table[pos] != -1)

    {   //如果已经求过这个值,则直接返回。

        return table[pos];

    }

    if (input [pos] == '0')

    {  //对串input当前扫描的pos位置为数字0时的处理

        table[pos] = 0;

        return 0;

    }

    else

    {

        if (pos >=input.size()-1 )

        {  //递归终止条件

            table[pos] = 1;

            return 1;

        }

        else

        {  //递归条用

            int tmp = (input[pos] - '0') * 10 + (input[pos+1] - '0');

            if (tmp<=26)

            {

                int res = Calc (input, pos+1) + Calc (input, pos+2);

               table [pos] = res;  //求得结果后填表,方便下次直接取答案

                return res;

            }

            else

            {

                int res = Calc (input, pos+1);

               table [pos] = res; //求得结果后填表,方便下次直接取答案

                return res;

            }

        }

    }

}

int main()

{

    string str;

    while (cin>>str, str!="0")

    {

        table.assign (str.size()+1, -1);

        cout<

    }

    return 0;

}

 

 

这样就可以通过了。

 

阅读(1434) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

05060102372009-03-31 08:51:36

有这么麻烦吗? 递推偏可