打印是我们生活中常见的问题,我们通过模拟打印任务,提出决策,让人们在不会等太久的前提下尽量提高打印质量。
首先需要对问题进行抽象,建立打印模型:
我们首先分析一下打印过程:
1)接受到打印任务(平均每一分钟接收一个打印任务,页数随机)
2)将打印任务排入队列
3)排到是进行打印
我们需要将连续时间离散化来模拟打印,以秒为单位
我们首先要搞清楚,接到打印任务并排队等待的过程与打印机进行打印工作的过程是相互独立的,举个例子来理解一下:
如上面的图,时间从0开始记,第一秒的时刻我们会做以下两个工作(这两个工作同时进行,并相互不影响):
1)第一秒这个时刻有没有新的打印任务能加入打印队列(相当于排队等候打印)?如果有,打印多少页?
2)第一秒这个时刻打印机是不是在工作?如果是,就工作1秒进入第二秒的状态。如果不是,判断有没有打印任务在排队,如果有,就取出队首的打印任务,打印一秒,进入第二秒的状态
第一秒的两个工作做完之后进入第二秒的状态进行相同的工作,一直到所设定的时间停止
过程理解清楚之后我们再来看时间:
我们将等待时间设为打印任务在刚开始进入队列起到被打印机接收开始打印止,这之间的时间为等待时间(可以理解为开始排队到排队完毕,开始服务之前的时间段)而打印机开始打印到打印完毕为打印时间,等待时间和队列长度有关,打印时间和打印页数与打印速度有关。
接下来是python模拟打印代码:
```python
# 用python实现ADT Queue
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
#打印类
class Printer:
def __init__(self,ppm):
self.pagerate = ppm #打印速度
self.currentTask = None #打印任务
self.timeRemain = 0 #任务倒计时
def tick(self): #打印一秒
if self.currentTask != None:
self.timeRemain = self.timeRemain - 1
if self.timeRemain <= 0:
self.currentTask = None
def busy(self): #打印忙?
if self.currentTask != None:
return True
else:
return False
def startNext(self,newtask): #打印新任务
self.currentTask = newtask
self.timeRemain = newtask.getPages() / self.pagerate
#队列类
import random
class Task:
def __init__(self,time):
self.timestamp = time #生成时间戳
self.pages = random.randrange(1,21) #生成随机打印页数
def getStamp(self):
return self.timestamp
def getPages(self):
return self.pages
def waitTime(self,currenttime):
return currenttime - self.timestamp
def newPrintTask(): #每一秒都有1/60的概率接到新的打印任务
num = random.randrange(1,61)
if num == 60:
return True
else:
return False
#模拟
def simlation(sumtime,rate):
printer_queue = Queue()
current_printer = Printer(rate)
waittime = []
for current_time in range(sumtime):
if newPrintTask(): #判断是否有新的打印任务
current_task = Task(current_time) #记录这个打印任务的开始排队时间
printer_queue.enqueue(current_task)
if (not current_printer.busy()) and (not printer_queue.isEmpty()):
newtask = printer_queue.dequeue() #取出队首的任务
waittime.append(newtask.waitTime(current_time)) #计算等待时间=当前时刻-之前记录的开始排队时间
current_printer.startNext(newtask)
current_printer.tick() #打印一秒
avgtime = sum(waittime) / len(waittime)
print(avgtime)
simlation(3600,0.2)
虽然有的同学理解清楚了过程,但是对应模拟打印还是有点模糊,我这里主要讲一下代码里面的那个等待时间是如何计算的,等待时间比较好理解,就是开始排队到开始打印之间的时间段,在代码中,我们的时间是从0开始的,比如说我们在第三秒的时候接到一个打印任务,此时这个任务的开始排队时间就记录为3,而我们循环到第五秒的时候第三秒那个进来的任务恰好被取出准备打印,当前时刻是第五秒,我们用5-3=2就是等待时间,因为这些打印任务没有特定的命名,所以是通过迭代的时间来区分任务的
当然我们也需要对类有一点了解