sicily 1001 Alphacode

http://soj.sysu.edu.cn/1001

没想到sicily的1001就那么难,动态规划,好像也不是很难想,不过得考虑清楚各种情况,很坑,好像一共是3种,还有一个注意的是,输入是合法的,如果只输入

30,那就没有一种解码方法了,这样的输入是不会出现的;还有,出现05这样的,也不能算是E......

开始了,假设dp[i]是前i个字符有多少种解码方式,因为每次考虑的是相邻两个数是否能组成一个小于26的数,所以大概能想到dp[i]会跟他的前一个值dp[i-1]有关,只是设想,接下来又要开始举栗子了:

input: 123

看第一个,1的时候是一种情况,1/,dp[1] = 1;

看12,有两种情况:1/2, 12/,dp[2] = 2;

再看123,关键的来了,dp[3]等于多少呢?看3和前一个2,小于26,可以组成一种解码方式,所以是1/23;然后,还有1/2/3,还有12/3,ok,3种了!

跟前面的对比一下:

1:   1/

2:   1/2, 12/

3:   1/23

      1/2/3, 12/3

看到了吧,第三种的画的斜线位置,是前两个画的斜线位置的叠加,就是红色位置的斜线,在第三种情况都出现了,so,dp[3] = dp[2] + dp[1];

当然,这只是一种情况,再来,如果当前是0的:

120

1:   1/

2:   1/2, 12/

3:   1/20

Obviously,第三种跟第一种是一样的啦!dp[3] = dp[1];

还有一种,如果当前的跟前一个合起来大于26,如下面的27:

127

1:   1/

2:   1/2, 12/

3:   1/2/7, 12/7

Obviously,第三种跟第二种是一样的啦!dp[3] = dp[2];

如果你以为没了,就错了:

107

1:   1/

2:   10/

3:   10/7

虽然第三种跟第二种是一样,dp[3] = dp[2],不过你得把前一个为0的情况归入到上一种情况,大功告成!

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 long long dp[5005];
 8 
 9 int main()
10 {
11     string s;
12     while(cin >> s)
13     {
14         if(s == "0")
15             break;
16         
17         int len = s.size();
18         
19         dp[0] = 1;
20         dp[1] = 1;
21         for(int i=1; i<len; i++)
22         {
23             if(s[i] != '0' && s[i-1] != '0' && (s[i]-'0' + (s[i-1]-'0') * 10) <= 26)
24                 dp[i+1] = dp[i-1] + dp[i];
25             else if(s[i] == '0')
26                 dp[i+1] = dp[i-1];
27             else
28                 dp[i+1] = dp[i];
29         }
30         cout << dp[len] << endl; 
31     }
32     return 0;
33 }
原文地址:https://www.cnblogs.com/dominjune/p/4386721.html