标签:
没想到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 }
标签:
原文地址:http://www.cnblogs.com/dominjune/p/4386721.html