三道题理解动态规划

动态规划是算法导论中介绍的最重要的几种基本算法之一,因为好长时间没有看书,再加上原来就理解的不深入,所以早就忘的差不多了,这两天正好因为一道面试题复习一下。

用几句话描述动态规划问题如下:

一个问题可以分解若干子问题,每一个子问题为一种状态,求出每一个状态的最优解,进而在它的帮助下求出下一个状态的最优解。

解决动态规划问题,最重要的步骤就是找出状态转移方程。有了状态转移方程就可以根据初始状态(边界)求出每一个状态的最优解。

动归问题的特点如下:

  • 最优子结构

  • 子问题重叠

  • 边界

  • 子问题独立

下面用三道题目帮组理解一下。

用最少的硬币得到给定的money

有1分,3分,5分3种硬币,如何使用最少的硬币数量得到12分。这个题目的状态转移方程如下。

d(i) = min(d(i-v(j)) + 1)

其中d是硬币数量,i是money总数,v(j)是第j个硬币的单位。初始值d(0)=0。代码如下:

    #! /usr/bin/env python
    # -*- coding:gbk -*-

    class Solution(object):
        def get_min_count(self, money, item_list):
            num_list = {}
            if money == 0:
                return 0
            num_list[0] = 0
            for i in range(1, money + 1):
                min = (1<<31) - 1
                index = -1
                for j in range(0, len(item_list)):
                    if item_list[j] <= i:
                        if min > num_list[i - item_list[j]] + 1:
                            min = num_list[i - item_list[j]] + 1
                            index = j
                print "cur_index:%d cur_item:%d pre_index:%d pre_num:%d" \\
                        %(i, item_list[index], i - item_list[index], num_list[i - item_list[index]])
                num_list[i] = min

            return num_list[money]

    if __name__ == "__main__":
        s = Solution()
        money = 12
        item_list = [1, 3, 5]

        print s.get_min_count(money, item_list)

最长升序子数列

题目的意思就是从一个数列当中找出最长的升序的子数列,比如”123412345123”的最长升序子数列是”12345”,这个题目的状态转移方程如下。

d(i) = d(i)+1 [if a[i] > a[j] i > j] or d(i) = 1 [if a[i] < a[j] i > j]

其中d是长度,i和j分别代表第i和j个字符,初始值d(0)=0。代码如下:

    #! /usr/bin/env python
    # -*- coding:gbk -*-

    class Solution(object):
        def max_up_seq(self, seq):
            if len(seq) == 0:
                return 0
            ret_len = {}
            ret_len[0] = 1
            max_len = 1
            max_seq_start = 0
            for i in range(0, len(seq) - 1):
                if seq[i + 1] >= seq[i]:
                    ret_len[i+1] = ret_len[i] + 1
                else:
                    ret_len[i+1] = 1
                    if max_len < ret_len[i]:
                        max_len = ret_len[i]
                        max_seq_start = i - max_len + 1
            if max_len < ret_len[len(seq) - 1]:
                max_len = ret_len[len(seq) - 1]
                max_seq_start = len(seq) - max_len
            return seq[max_seq_start:max_seq_start + max_len]

    if __name__ == "__main__":
        s = Solution()
        print s.max_up_seq([1,2,3,4])
        print s.max_up_seq([1,2,3,4,2,3,3,4])
        print s.max_up_seq([1,2,1,2,3,4,7,8,9,1,2,4,5,7])

0-1背包问题

这道题是动态规划最经典的问题,网上求解方法很多。题目内容大致是, 有5个商品,背包的体积为10,他们的体积为 c[5] = {2, 2, 6, 5, 4}, 价值为 v[5] = {6, 3, 5, 4, 6},如何利用背包的体积放入价值最大的物品。一个物品只能放入或者没有放入背包。

状态方程如下。

V[i][j]=max(V[i-1][j],f[i-1][j-ci]+vi)

其中C是背包体积,V[i][j]放入第i个物品总体积为j时的总价值,c[i]是第i个商品体积,v[i]是第i商品价值。代码如下:

    # include <cstdio>

    const int MAX_NUM = 100;

    int V[MAX_NUM][MAX_NUM];

    int bag(int volum, int n, int* weight, int* value) {
        if (volum == 0) {
            return 0;
        }
        for (int i = 0; i < n + 1; ++i) {
            V[i][0] = 0;
            // printf("weight:%d value:%d\", weight[i], value[i]);
        }
        for (int i = 0; i < volum + 1; ++i) {
            V[0][i] = 0;
        }

        printf("volum:%d num:%d\", volum, n);

        for (int j = 1; j < volum+1; ++j) {
            for (int i = 1; i < n+1; ++i) {
                int max = V[i -1][j];
                // printf("max:%d ", max);
                if (j < weight[i]) {
                    // printf("j<weight[i] ");
                    V[i][j] = V[i - 1][j];
                } else {
                    // printf("j>=weight[i] ");
                    if (max < V[i - 1][j - weight[i]] + value[i]) {
                        max = V[i - 1][j - weight[i]] + value[i];
                    }
                    V[i][j] = max;
                }
                printf("%d %d item:%d\", i, j, V[i][j]);
            }
        }


        return 0;
    }

    int main() {
        int weight[6] = {0, 2, 2, 6, 5, 4};
        int value[6] = {0, 6, 3, 5, 4, 6};
        bag(10, 5, weight, value);
        printf("max value: %d\", V[5][10]);

        return 0;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值