动态规划法

一、基本思想

  1. 将待求问题分解为若干个子问题,先求子问题,然后将这些子问题的解得到为原问题的解。
  2. 用分治法解决同类问题时,相同的子问题会被求解多次。动态规划法用一张表来记录所有已解决问题的子问题的答案。

二、 步骤

  1. (划分)多阶段决策过程,每步处理一个子问题,界定子问题的边界(初值问题)。
  2. 列出优化函数的递推方程及初值(无比关键)。
  3. 问题要满足优化原则或者最优子结构性质(一个最优决策序列的任何子序列本身一定是相对于子序列的初始和结束状态的最优决策序列)。

三、典型实例

  1. 0-1背包问题:
    有一个背包,他的容量为C(Capacity)。现在有n种不同的物品编号分别为0、1…n-1。其中每一件物品的重量为w(i),价值为v(i)。问可以向这个背包中放入哪些物品,使得在不超过背包容量的基础上,背包内物品价值最大。
public int maxValue(int[] weights, int[] values, int w)
    {
        int n = weights.length;
        int[][] vw = new int[n][w + 1];
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < w + 1; j++)
            {
                vw[i][j] = -1;
            }
        }

        vw[0][0] = 0;
        vw[0][weights[0]] = values[0];
        for (int i = 1; i < n; i++)
        {
            for (int j = 0; j <= w; j++)
            {
                if (vw[i - 1][j] >= 0)
                {
                    vw[i][j] = vw[i - 1][j];
                }
            }

            for (int j = w - weights[i]; j >= 0; j--)
            {
                if (vw[i - 1][j] >= 0)
                {
                    int v = vw[i - 1][j] + values[i];
                    if (v > vw[i][j + weights[i]])
                    {
                        vw[i][j + weights[i]] = v;
                    }
                }
            }
        }

        int maxValue = 0;
        for (int i = 0; i <= w; i++)
        {
            if (vw[n - 1][i] > maxValue)
            {
                maxValue = vw[n - 1][i];
            }
        }

        return maxValue;
    }

    public static void main(String[] args)
    {
        int[] weights = {3, 4, 7, 8, 9};
        int[] values = {4, 5, 10, 11, 13};
        final Packet packet = new Packet();
        System.out.println(packet.maxValue(weights, values, 17));
    }
  1. 最大子段和问题:求一个序列的最大子段和即最大连续子序列之和。
    例如序列[4, -3, 5, -2, -1, 2, 6, -2]的最大子段和为11=[4+(-3)+5+(-2)+(-1)+(2)+(6)]。
    原问题:考虑最大子段和原问题:给定nn个数(可以为负数)的序列(a1,a2,…,an)(a1,a2,…,an),求max{0,max1≤i≤j≤n∑jk=iak}max{0,max1≤i≤j≤n∑k=ijak}
    子问题界定:设前边界为1,后边界为ii,且C(i)C(i)是子序列A[1,…i]A[1,…i]必须包含元素A[i]A[i]的向前连续延伸的最大子段和:
    C[i]=max1≤k≤i{∑j=kiA[j]}
    C[i]=max1≤k≤i{∑j=kiA[j]}

递推方程满足
C[i]=max{C[i−1]+A[i], A[i]}i=2,…,nC[1]={A[1] ifA[1]>00 ifA[1]<0
C[i]=max{C[i−1]+A[i], A[i]}i=2,…,nC[1]={A[1] ifA[1]>00 ifA[1]<0
遍历所有以i (1≤i≤n)i (1≤i≤n)为后边界的最大子段和CiCi得出最优解:
OPT(A)=max1≤i≤n{Ci}

int MaxSubsequenceSum(const int A[], int n)
{
    int tempSum = A[0];
    int maxSum = 0;
    for (int j = 0;j < n;j++)   // 子问题后边界
    {
        tempSum = (tempSum + A[j]) > A[j] ? (tempSum + A[j]) : A[j];
        if (tempSum > maxSum)   // 更新最大和
            maxSum = tempSum;
    }
    return maxSum;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值