动态规划(一)

动态规划算法,概念、策略、步骤及示例字符串编码

Posted by HonorJoey on March 5, 2020

动态规划的概念和策略

概念

每次决策都依赖于当前状态,又随即引起状态的转移。一个决策的序列就是在变化的状态中产生出啊来的,所以,这种这种多阶段最优化决策解决问题的过程称为动态规划。

动态规划的基本思想和策略

将带求解的问题分解为若干个子问题,按顺序求解子问题,前一子问题的姐为后一子问题的求解提供了有用的信息。

能用动态规划求解的问题一般具有三个性质:

  • 最优化原理
  • 无后效性
  • 有重叠子问题

动态规划求解问题的步骤:

  • 划分阶段
  • 确定状态和状态变量
  • 确定决策并写出状态转移方程
  • 寻找边界条件

示例

字符串解码

题目要求:

一个包含字母的消息被加密之后变成了一个只包含数字的字符串,但是我们现在知道加密规则:
‘A’->1
‘B’->2

‘Z’->26
现在给定一个已经加密的只包含数字的字符串,求出改字符串有多少种被解密的方法。例如,”12”->”AB”,”12”->”L”

思路:

这是一个典型的DP问题,假设定义一个数组,dp[i]为到第i个字符所能组成的所有编码方式的个数,那么对于dp[i+1]来说,肯定至少和dp[i]一样多,如果第i个字符和第i+1个字符能合成一个字符,那么dp[i+1] += dp[i-1]

代码(C++):

#include <iostream>

#include <string>

#include <vector>

using namespace std;

/**
 * 思路:

 * 这是一个典型的DP问题,假设定义一个数组,dp[i]为到第i个字符所能组成的

 * 所有编码方式的个数,那么对于dp[i+1]来说,肯定至少和dp[i]一样多,如果

 * 第i个字符和第i+1个字符能合成一个字符,那么dp[i+1] += dp[i-1]

 */

int Decode_num(string &str) {
    vector<int> vec(str.size(), 1);
    if (str.size() < 2)
        return 1;
    if (str[0] == '1' || (str[0] == '2' && str[1] <= '6'))
        vec[1] = 2;
    int i;
    int temp;
    for (i = 2; i < str.size(); i++) {
        if (str[i] >= '0' && str[i] <= '9')//判断是否合法字符
            vec[i] = vec[i - 1];
        else
            return 0;
        temp = str[i - 1] - '0';
        temp = temp * 10 + str[i] - '0';
        if (str[i - 1] != 0 && temp <= 26)
            vec[i] += vec[i - 2];
    }
    return vec[str.size() - 1];
}


int main() {
    string str("1231725");
    int ret = Decode_num(str);
    cout << ret <<endl;
    return 0;
}

代码(Go):

package main

import "fmt"

/**
 思路:

 这是一个典型的DP问题,假设定义一个数组,dp[i]为到第i个字符所能组成的

 所有编码方式的个数,那么对于dp[i+1]来说,肯定至少和dp[i]一样多,如果

 第i个字符和第i+1个字符能合成一个字符,那么dp[i+1] += dp[i-1]

*/
func DecodeNum(str string) int {
	var s []int
	s = append(s, 1)
	if len(str) < 2 {
		return 1
	}
	if str[0] == '1' || (str[0] == '2' && str[1] <= '6') {
		s = append(s, 2)
	}
	i, temp := 0, 0
	for i = 2; i < len(str); i++ {
		if str[i] >= '0' && str[i] <= '9' {
			s = append(s, s[i-1])
		} else {
			return 0
		}
		temp = int(str[i-1] - '0')
		temp = temp*10 + int(str[i]-'0')
		if str[i-1] != '0' && temp <= 26 {
			s[i] += s[i-2]
		}
	}
	return s[len(str)-1]
}

func main() {
	str := "1231725"
	fmt.Println(DecodeNum(str))
}