甜品店切蛋糕问题(动态规划,Go语言实现)
问题重现: 小Y最近在甜品店工作,其工作是切蛋糕。现在有n个顾客来购买蛋糕,并且每个顾客有一个到达的时间,以及需要买的蛋糕的长度ai。由于小Y每次只能服务一个顾客,【问题严谨性补充:而顾客如果进店没有服务员立刻为他服务,他将离开】所以对于相冲突的顾客没有办法提供服务。问小Y最多能为多少位顾客提供服务。小Y能够决定是否卖蛋糕给某个顾客。如果答应顾客要买长度为ai的切糕,那么小Y还要将蛋糕切成单位长度给顾客。如果对ai的蛋糕切成x和ai-x,所花的时间代价为x*(ai-x)。例如,当一个用户在1时刻,需要长度为4的蛋糕,此时小Y可以将其先切成2分长度为2的,花费为4,再将两段长度为2的分别切成1,1的,花费分别为1和1,则总花费时间为4+1+1 = 6, 则小Y为该用户服务时间为6.
已知第i位顾客进店时间,以及购买蛋糕大小。【作者特别说明:在原题上稍有修改,本文重在讲清思想】
分析:(转载请注明出处和作者名) 涉及问题一:大小为n的蛋糕需要多长时间切成单位长度?
f(x)=x*(n-x) 绘制函数草图可以得到:x=1时得到最小值,也就是说每次1单位1单位的切
用数学归纳法证明上述的解得到的最终和解也是最小的 n=2时 f(x)显然得到的最小解 n=3时 f(x)显然得到的最小解 n=4时 f(x)显然得到的最小解 ... 假设n=i-1时也能得到最小解 n=i时 切成x 和(i-x) 显然x必然是前面已经推出的n的一个解,i-x也是前面推出的一个解,而f(x)的最优解和f(i-x)就是每次1单位1单位的切 这时只要保证x*(i-x)值最小即可,最小情况x=1,也就证明了每次1单位1单位的切的解得到的最终和解也是最小的。
涉及问题二:已知各位顾客的进店时间和购买蛋糕大小,如何选出最佳服务对象?
这个问题至少可以使用贪心策略来解决,似乎包含了动态规划,看起来很像01背包问题
动态规划: f[t]表示t时间内在前i个人已服务完的服务对象人数 s表示第i个人需要的服务时长 r表示第i个人达到时间点
㈠对于是否选择服务第i个人有两种情形 ①选择,但要满足完成第i人的服务后时间不超过t (如果选择了第i个人,可能就存在不允许选前i-1个人中的某些人) f[t]=f[i-1][r]+1 【t>=r+s】 ②不选,不改变在t时间的策略 (之所以不选的原因,就是因为第i个人到时,小Y还没有为前面的人服务完,又或者如果选了第i人会耽误后面更多的人) f[t]=f[i-1][t] ㈡决策退出条件(决策既知条件) 时间没有负数,所以无需判断 i==0 返回1或0 解释:因为i==0即最后一个人,如果满足条件t >= r[0]+s[0],返回1 ㈢决策入口条件 t=max{s+r}
于是可以得出: 状态转移方程为:f[t]=max{ f[i-1][t-s] (t>=r+s), f[i-1][t]}
以下给出Go语言实现代码:
package main
import (
"fmt"
)
/*求最小服务时长,每次1单位1单位的切,得到的是最小解*/
func smin(n int32) int32 {
if n&1 == 0 {
return (n / 2) * (n - 1)
}
return (n - 1) / 2 * n
}
/*求每个顾客的时间*/
func serverTime(s, lenght []int32, maxLen int32) {
for i := range lenght {
s[i] = smin(lenght[i])
}
}
/*求二者最大值*/
func maxInt32(a, b int32) int32 {
if a > b {
return a
}
return b
}
/*DP问题核心 作者:天之 CSDN博客:http://blog.csdn.net/WAPWO?viewmode=contents*/
func dptz(i, t int32, r, s []int32) int32 {
if i == 0 {
if t >= r[0]+s[0] {
return 1
}
return 0
}
if t >= r[i]+s[i] {
return maxInt32(dptz(i-1, r[i], r, s)+1, dptz(i-1, t, r, s))
}
return dptz(i-1, t, r, s)
}
/*求最后结束时间*/
func endTime(r, s []int32) int32 {
var max, tmp int32 = 0, 0
for i := range r {
tmp = r[i] + s[i]
if max < tmp {
max = tmp
}
}
return max
}
func main() {
//蛋糕长度、先来后到的时间和服务时间
length := []int32{2, 2, 3, 4}
r := []int32{5, 5, 6, 10}
s := make([]int32, 4)
serverTime(s, length, 4)
fmt.Println(dptz(3, endTime(r, s), r, s))
}
- Scala语言基础之结合demo和spark讲实现链式计算
- Spark高级操作之json复杂和嵌套数据结构的操作二
- Spark高级操作之json复杂和嵌套数据结构的操作一
- hadoop系列之基础系列
- Spark的调度系统
- Spark Structured Streaming的高效处理-RunOnceTrigger
- Spark度量系统相关讲解
- Spark Structured Streaming高级特性
- Table API&SQL的基本概念及使用介绍
- 使用Linq to Sql 创建数据库和表
- Flink DataSet编程指南-demo演示及注意事项
- 解决 wcf HTTP 无法注册 另一应用程序正在使用 TCP 端口 80
- 构建Flink工程及demo演示
- F-Stack之kqueue封装为epoll介绍
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 更新Android Studio 3.0碰到的问题小结
- android实现一个图片验证码倒计时功能
- Android添加glide库报错Error:Failed to resolve:com.android.support:26.0.2的解决
- Android多线程下载示例详解
- 详解Android Gradle插件3.0挖坑日记
- Android开发之拼音转换工具类PinyinUtils示例
- Android多线程断点续传下载示例详解
- Android设备与外接U盘实现数据读取操作的示例
- [Alibaba-ARouter]浅谈简单好用的Android页面路由框架
- android屏幕圆角实现方法的示例代码
- Android开发中日期工具类DateUtil完整实例
- Android模仿实现微博详情页滑动固定顶部栏的效果实例
- Android EventBus(普通事件/粘性事件)详解
- Android实现EventBus登录界面与传值(粘性事件)
- Android自定义LinearLayout布局显示不完整的解决方法