数学建模动态规划的小案例之R代码实现——生产计划问题

1、问题描述

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

2、解题思路

这一类生产计划问题(Production planning problem),阶段按计划时间自然划分,状态定义为每阶段开始时的储存量x(k),决策为每个阶段的产量u(k),记每个阶段的需求量(已知量)为d(k),则状态转移方程为:

		x(k+1) = x(k) + u(k) − d(k)  ( x(k)≥0, k=1,2,...,n )

设每阶段开工的固定成本费为a,生产单位数量产品的成本费为b,每阶段单位数量产品的储存费为c,阶段指标为阶段的生产成本和储存费之和,即

if u(k)>0
				v(x(k), u(k)) = cx(k) + (a + bu(k)) 

if u(k)=0
				v(x(k), u(k)) = cx(k) + 0

最优值函数f(x(k))为从第k段的状态x(k)出发到过程终结的最小费用,满足 :

				f(x(k)) = min(v(x(k), u(k)) + f(x(k+1)))

3、R程序实现

# 每阶段单位数量产品的储存费为c
C = 0.5;

# 每阶段开工的固定成本费为a
A = 3;

# 生产单位数量产品的成本费为b
B = 1;

# 市场对该产品的需求量数组
ds <- c(2, 3, 2, 4);

# 市场对该产品的需求量函数
d <- function(k) {
  return (ds[k])
};

# 生产目标,所有初始化为NA,在每次遍历的时候,需要更新这个值
us <- rep(NA, times=length(ds));
u <- function(k) {
  return (us[k]);
}


# 每阶段开始时的储存量x(x)
x <- function(k) {
  if(k <= 1) {
    result <- 0;
  } else {
    result <- x(k-1) + u(k-1) - d(k-1);
  }
  return (result);
}

# 阶段的生产成本和储存费之和
vs <- c();
v <- function(k) {
  if(u(k) == 0) {
    vs[k] <- C*x(k);
  }
  if(u(k)>0) {
    vs[k] <- C*x(k) + (A + B*u(k));
  }
  return (vs[k]);
}

f <- function(k) {
  # 设置终止条件,如果为第k+1季度,则返回
  #f(x(k))=min(v(x(k), u(k)) + f(x(k+1)))
  
  if(k == (length(ds)+1)) {
    result <- 0;
  } else {
    result <- v(k) + f(k+1);
  }
  
  return (result);
}

uss <- expand.grid(s1=c(0:sum(ds)), s2=c(0:sum(ds)), s3=c(0:sum(ds)), s4=c(0:sum(ds)));
uss <- data.matrix(uss[which(rowSums(uss)==sum(ds)),]);

#i<- 2
#uss[which(rowSums(matrix(uss[,1:i], ncol=i))>=sum(ds[1:i])),];

for(i in 1:length(ds)) {
  uss <- uss[which(rowSums(matrix(uss[,1:i], ncol=i)) >= sum(ds[1:i])),];
}

rs = c();
for(i in 1:nrow(uss)) {
  # 重新设置us值
  us <- uss[i,];
  rs[i] <- f(1);
}

min(rs)
uss[which(rs == min(rs)),]

4、输出结果

> min(rs)
[1] 20.5

> uss[which(rs == min(rs)), ]
     s1 s2 s3 s4
870   5  0  6  0
6920  7  0  0  4
收集了2004年(第一届)至今中(全)国研究生数学建模竞赛获奖数据,并基于R语言,进行了数据处理和可视化的工作。 这项工作最初的起因是,作者和队友在2015、2016、2017年参赛并获奖后,好奇一共有多少人连续获奖以及他们来自于哪个省份和学校。于是2017年底,我开始收集数据、敲代码。由于当时正值毕业,也面临着从matlab转出选语言的问题,认准R语言的我便开始使用R来写这部分代码,因此当时那一版惨不忍睹。2018年9月15日,台风山竹正面袭击广州深圳,被迫呆在家里的我,发现正好是当年落户杯开赛的日子,于是我决定把这个代码重写了一遍,并发布到github上。2020开年的新冠肺炎疫情期间,没法去办公室的我,看了Hadley 大神的Advanced R一书,并整合自己2019年所学,开始重新审视自己的编程水平,于是决定再一次修改这个代码,并且决定,以后每年都要来修改一次,以见证每年收获和进步。 关于项目的几个说明: 中国研究生数学建模竞赛(原名全国研究生数学建模竞赛),官网网址(新),官方网址(旧),2004年开办,每年9月开赛、11月~12月会公布当年获奖结果,旧网址曾经有历年数据,不过目前404了; 官方公布的获奖名单,包含一等奖、二等奖、三等奖以及成功参与(参赛、参加)奖,但是基本上参赛、提交并未被认定为作弊就能拿到成功参与奖,所以这里将获奖名单视为参赛名单,其中的一二三等奖视为获奖; 部分年份获奖名单中无题型信息,则视其题型全部为N; 对于个人“连续获奖”这个概念,每个版本可能有不同算法,但基本原则是: 鉴于信息有限,只考虑同名、同学校在连续年份的获奖情况为“连续获奖”,即忽略“山大张三在2005年获奖后转学到中大并于2006年获奖” 鉴于信息有限,不区分同名不同人、但同校名的获奖情况,即将“山大张三于2005年获奖然后另一个也叫张三的山大学生于2006年获奖”,视为连续2次获奖 如果张三于2005年获奖,并于2007、2008年获奖,则将其视为两次连续获奖,第一次为1连,第二次为2连
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值