动态规划学习中的一道题目

记得初中时候的一篇文章说,做学问,必须要有学和问两个方面。

做了一些动态规划题目之后偶然看到这个介绍动态规划的文章。然后遇见第一道题目就卡壳。

经过反思文章以及自己思考,总算对题目有了一些理解。下面分享给大家,初学者们看到这个题目不至于太过茫然——像我一样。

工厂生产某种产品,每单位(千件)的成本为1(千元),每次开工的固定成本为3(千元),工厂每季度的最大生产能力为6(千件)。经调查,市场对该产品的需求量第一、二、三、四季度分别为        2,3,2,4(千件)。如果工厂在第一、二季度将全年的需求都生产出来,自然可以降低成本(少付固定成本费),但是对于第三、四季度才能上市的产品需付存储费,每季每千件的存储费为0.5(千元)。还规定年初和年末这种产品均无库存。试制订一个生产计划,即安排每个季度的产量,使一年的总费用(生产成本和存储费)最少。

学:

1、动态规划的实质是分治思想和解决冗余,因此,动态规划是一种将问题实例分解为更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法策略。

2、动态规划算法的基本步骤

  1. 划分阶段
  2. 选择状态
  3. 确定决策并写出状态转移方程
  4. 写出规划方程(包括边界条件)。。。。。。(还有很多比较重要的内容,读者百度此题目后可以看到不同完整度和版本的文章)

问:

此题目的阶段如何划分、状态如何确定、决策有哪些、状态之间有什么关系。。。

思路:

首先应该是应该选择何种变量来划分问题的各个状态——即找到想要求得结果时需要反复计算的一种状态。

已经知道有四个季度,可以选择各个季度的产量,还有一个附加条件——一年的开始和结束都没有库存

那么是否可以用这三个变量(季度,产量,季末库存)来表示状态呢?

 

开始分析:状态之间的关系。

因为有0.5,开始定义一个double 型的三维数组dp[i][j][k]表示第i季度,产量为j,剩余量为k时的最少花费。

那么,问题来啦

因为同一个状态dp[i][j][k]有多个来源,上一季度的产量和剩余量都不确定,如何设置搜索过程来确定这个最小值,

似乎子问题并不是那么容易解决。

 

但是两阶段之间有一重要的关系:

本季度剩余量k==本季度产量+上季度库存量-本季度需求。

因此dp[i][j][k]=min(dp[i][j][k],dp[i-1][0...6][k+本季度需求-本季度产量])

只要再设置一层循环0到6就可以找出dp[i][j][k]最小值。

这样设置一个四层循环,然后循环结束后输出dp[4][0...6][0] 的最小值,就是本题的最终结果。

 

大体框架思路有了,下面就是代码实现:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int main()
{
    double dp[5][7][7];
    double cost[7][7];
    int d[5]={0,2,3,2,4};//各个季度的需求 
    int i,j,k,l,m,temp,c;
    
    for(i=0;i<7;i++)
    for(j=0;j<7;j++)
    {
    cost[i][j]=0.5*i+(j==0?0:j*1+3);//因为题目中多次用到库存为i生产为j的一季度消费,故初始化。 
    if(j==i-2)
    dp[1][i][j]=cost[0][i];//第一季度比较特殊,开始时库存为0
    else
    dp[1][i][j]=-1.0;//负数代表不合法 
    }
    
    for(i=2;i<=4;i++)
    for(j=0;j<=6;j++)
    for(k=0;k<=6;k++)
    {
        temp=k+j-d[i];
        if(temp>=0)//边界问题 
        {
            c=-1;
            dp[i][j][k]=99;
            for(m=0;m<=6;m++)
            if(dp[i-1][m][temp]>0)//必须是合法数据 
            {
                dp[i][j][k]=min(dp[i][j][k],dp[i-1][m][temp]+cost[temp][j]);
                c=0;
            }
            if(c)
            dp[i][j][k]=-1;//未找到合法数据 
        }
        else
        dp[i][j][k]=-1;
    }
    double cnt=99;
    for(i=0;i<=6;i++)
    if(dp[4][i][0]>0)
    cnt=min(cnt,dp[4][i][0]);//输出最小值 
    printf("%lf\n",cnt);
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/KIKIKS/p/4298145.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值