动态规划实例:"Alphacode" From Sicily 1001

动态规划实例之 Alphacode

1.问题描述:

     Alphacode 题目描述

2.问题背景:

 动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)

3.问题分析:

     在开始做这道题的时候我首先想到的是用分治的思想来求解这道题(使用递归来做),但后来才发现这样会导致重复记数,并且很难解决这个问题;然后才想起能使用动态规划的思想来解决这个问题,好的废话少说,进入正题。

      结合题目背景,我们从无到有逐个增加数字字符,首先设置两个状态标识pre_status(加入当前的数字字符str[i]前,有多少种译码方法), s_pre_status(加入数字字符str[i-1]前,有多少种译码方法);另外使用total_num来记录最终的译码方案。然后,确定状态转移方程,如果当前的数字字符str[i]能和前一个字符str[i - 1]组合成一个合法的译码数值(10 < int_value < 27),那么total_num = pre_status + s_pre_status;否则,total_num = pre_status;然后这两种情况都要s_pre_status = pre_status,pre_status = total_num完成状态的转移。

4.问题注意事项:

     1.确定字符0是否为当前字符,如果不是就正常按照之前的状态转移算法处理;如果是total_num = s_pre_status,因为0必须和当前字符的前一个字符组合成一个合法的整数值(比如20,10等,0不能单独进行进行译码,由题意可知)。

      2.在算法的初始阶段,注意正确确定每个状态的合法值。(具体请参见代码)

5.问题参考解答:

         

#include<iostream> 
07. #include<string>
08. using namespace std;
09. /*判断能否与前一个字符组成合法值*/
10. bool isValid(string str, int i) {
11. if (i == 0) return false;
12. int num = (str[i - 1] - '0') * 10 + str[i] - '0';
13. return (num > 10 && num <= 26);
14. }
15.  
16. int main()  {
17. string str;
18. while(cin >> str && str != string("0")) {
19. int total_num = 0;
20. /*record the previous status*/
21. int pre_status = 0, s_pre_status = 0;
22.  
23. for (int i = 0; i < str.length(); i++) {
24. if (i == 0) {
25. total_num = s_pre_status = 1;/*第一个字符,total_num和s_pre_status置为1*/
26. }
27. if (i == 1) {
28. if (isValid(str, i) && str[i] != '0') {/*注意这里有两个判断条件,特别是后者*/
29. total_num = pre_status = 2;
30. else {
31. total_num = pre_status = 1;/*如果第二个字符为0,那么必须和第一个字符组合*/
32. }
33. }
34.  
35. if (i > 1) {
36. if (str[i] != '0') {
37. if (isValid(str, i)) {/*如果当前字符能和上一个字符组合,则总的种类数为前两个种类数之和(此时可以与上个字符结合或不结合)*/
38. total_num = pre_status + s_pre_status;
39. s_pre_status = pre_status;
40. pre_status = total_num;
41. else {
42. total_num = pre_status;/*如不能组合,则总数为上一个种类数*/
43. s_pre_status = pre_status;
44. pre_status = total_num;
45. }
46. else {
47. total_num = s_pre_status;/*如果当前字符为0,total_num就为上上步的种类数,因为上个字符要与当前字符结合*/
48. s_pre_status = pre_status;
49. pre_status = total_num;
50. }
51. }
52. }
53. cout << total_num << endl;
54. }
55. }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值