Sicily.1001.Alphacode

 Sicily.1001.Alphacode

一道经典的DP题。一看题就去百度找答案了,找到不少博文是解这道题,但都只是把解决方法写出来,没有解释,那我来解释一下:

首先,解这道题的基本思路(不考虑各种极端情况)是:

一个字母码的解数=去掉最后一位的解数+去掉最后两位的解数

即递归方程为:

dp[i] = dp[i-1]+dp[i-2]

比如:“25114”的解数 = “2511”的解数+“251”的解数。为什么是两位呢?因为英文字母编码最多是2位(26),因此要考虑新加进来的这位是否会和前面一位形成新的解情况,同时也要考虑只因为加了自身形成的解情况(其实就是原解数,因为把新位独立看待并不改变解数)。

 

其次到了考虑一些比较极端的情况,首先就是‘0’的出现,一些博文一开始就说dp[i] = dp[i-2](i==0),但没解释为什么。其实,在保证了输入的字母码是正确的前提下,那么新加入的这个0必然不会使前面出错,即前面不会出现大于2的值(当然也不会出现连续的0),因此这个0必然要和前面的1或2形成一个字母,因此前面这一位就废了,相当于一定要特意拿出来和0以保证字母码无误。因此只要考虑dp[i-2]的解数就可以了。

 

最后还要考虑0以及其他数出现在字母码的第二位即下标为1的情况。为什么要考虑这个,因为我们之前写的递归式都会有下标为i-2的情况,不考虑这个明显数组越界。

首先我们就设了dp[0]=1.假如第二位是0,那这个0必然要和第一个数形成一个数,故dp[1]=1;假如第二位不是0,但如果这个数和第一个数组成的数大于26,那必然只能分开来形成字母,dp[1]还是为1;否则就可以是2了。

 

最后一点说说这个代码的架构,虽然这是一个只有37行的代码,但我认为一个程序的架构对程序的可读性是很重要的:我是按照判断到的这一位是否为0、是否与前一位组成合法字母(小于26)、是否不构成合法字母,来进行对dp数组的计算。


感谢博主:http://www.cnblogs.com/mrlaker/archive/2012/07/17/2595271.html 的代码,我参考了他的架构和思路,谢谢!


我的实现:

/*
 * Sicily1001Alphacode.cpp
 *
 *  Created on: 2014年7月5日
 *      Author: Prophet
 */
#include<iostream>
#include<cstring>
using namespace std;

int main(){
	string s;
	cin>>s;
	while(s[0]!='0'){
		int length = s.length();
		long dp[length];
		dp[0]=1;//只有一个数字(且不为0)的时候必然是只有1中拆解情况
		for(int i=1;i<length;i++){
			if(s[i]=='0'){
				if(i==1)
					dp[i]=dp[i-1];
				else
					dp[i]=dp[i-2];
			}
			else if(s[i-1]=='1'||(s[i-1]=='2'&&s[i]<='6')){
				if(i==1)
					dp[i]=dp[i-1]+1;
				else
					dp[i]=dp[i-2]+dp[i-1];
			}
			else//与前面数字构成非法字母,因此只能单独出来,故不加1
				dp[i]=dp[i-1];
		}
		cout<<dp[length-1]<<endl;
		cin>>s;
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值