首页 > 编程语言 >呼叫中心的离散事件模拟(C++_模拟)

呼叫中心的离散事件模拟(C++_模拟)

时间:2023-06-20 10:03:23浏览次数:33  
标签:node last temp Dlist 用户 C++ 离散 模拟 first


题目

       模拟网上书店的电话接待台接电话(离散事件)的过程。用户在打电话咨询时,先输入自己的标识(如姓名或会员
号),然后进入排队等待被接听电话。xauat 服务人员会根据该用户在书店已购买书籍的累计消费情况对拨入的电话进
行排序。累计消费超过 3000 元的为 1 类用户,最先得到服务;累计消费不到 3000 元、但已满 2000 元的 2 类用户在没
有 1 类用户情况下会得到服务;累计消费不满 2000 元、但已满 1000 元的 3 类用户在没有前两类用户情况下会得到服
务;累积消费不满 1000 元的用户为 4 类用户,在没有前三类用户情况下会得到服务。同类用户根据时间先后确定被接
听的次序。
这些离散事件事先存入文件 sample.txt,程序接收的离散事件需要从 sample.txt 进行,因此程序在运行时需要使用
输入重定向的方式将标准输入流指定为 sample.txt。
该文件格式如下:
首行为整数 N,表明文件接下来有 N 行离散事件(需要接听的电话)。
接下来的 N 行对应 N 项拨入电话,每行离散事件包含 4 项信息,之间使用一个空格隔开。信息格式如下:

<timestamp> <Name> <status> <duration>

<timestamp>指该电话的拨入时间点,其值为当时所对应的系统时间片编号(从 0 开始算起)。
<Name>指拨入电话的用户姓名(不考虑重名情况),姓名是字符串,中间不允许有空格。
<status>指该用户的等级,从 1 至 4,按照上面的叙述,根据累计消费额分成 4 类用户。
<duration>指该离散事件需要持续的时间片长度。
存储离散时间的示例输入文件 sample.txt 如下(分割线中内容):
---------------------------------------------

3				 <---表明下面共有 3 行,对应 3 通拨入的电话
0 Andrew 1 2 	 <---表明 1 类用户 Andrew 在 0 时间片拨入电话,需持续 2 个时间片(将占用 0、1 时间片)
0 Chris 4 1 	 <---表明 4 类用户 Chris 在 0 时间片拨入电话,需持续 1 个时间片
1 Brian 2 1 	 <---表明 2 类用户 Brian 在 1 时间片拨入电话,需持续 1 个时间片

--------------------------------------------- 我们可以分析上面的数据,首时间片 0 号开始时,有两通电话生成,一个是 1 类用户 Andrew ,一个是 4 类用户
Chris,则应先接 1 类用户 Andrew 电话,由于其需持续两个时间片,故应占 0、1 两个时间片。因此 0 号时间片
中系统应输出有两通电话的信息,同时还要输出开始处理 1 类用户 Andrew 电话。
当 1 号时间片开始时,有 1 通电话生成,是 2 类用户 Brian 的电话。因此 1 号时间片下,应输出新到的这通电
话,由于仍旧在处理 Andrew 的电话,所以在这个时间片不再输出开始处理 1 类用户 Andrew 电话。
当 2 号时间片开始时,没有电话生成。由于已经完成了 1 类用户 Andrew 电话,因此服务人员需要接听其他电
话,这时系统已有两通正在等待接听的电话,所以按照优先级原则,晚到的 2 类用户 Brian 的电话需要接听,因
此在这个时间片需要输出开始处理 2 类用户 Brian 电话。该电话时长为一个时间单元。
当 3 号时间片开始时,没有电话生成。由于已经完成了 2 类用户 Brian 电话,因此服务人员需要接听其他电话,
这时系统仅有 1 通正在等待接听的电话,4 类用户 Chris 的电话被接听,因此在这个时间片需要输出开始处理 4
类用户 Chris 电话。该电话时长为一个时间单元。
当 4 号时间片开始时,没有电话生成。也没有其他需要接听的电话,所以该时间片不需要输处其他信息。系
统模拟也结束了。
为清楚起见,在每一时间片开始,系统都提示如下信息:

Starting tick #<tick>

这里的<tick>表示时间片编号,从 0 开始。某人电话生成时,输出格式如下:

Call from <Name> a Level<status> member

开始处理某人电话时,输出格式如下:

Answering call from <Name>

这里的<Name><status>与前面一致。
对于上面的存储离散时间的示例输入文件 sample.txt,程序运行后应输出如下信息(分割线中内容):
--------------------------------------------- 盘符> call < sample.txt <—注意这里使用了输入重定向,表示输入设备是文件,不是键盘

Starting tick #0
Call from Andrew a Level1 member
Call from Chris a Level4 member
Answering call from Andrew
Starting tick #1
Call from Brian a Level2 member
Starting tick #2
Answering call from Brian
Starting tick #3
Answering call from Chris
Starting tick #4

--------------------------------------------- 编写程序,按照上述要求完成离散事件的模拟任务。实现完后,可以变动 sample.txt 内容执行程序,检验程序功能
是否满足上面的要求,运行正常。

Process

具体思路我都写在注释里了,emmm.

Code

Dlist.h

#ifndef __DLIST_H__
#define __DLIST_H__
// Get a definition for NULL
#include <iostream>;
using namespace std;
class emptyList {
	// OVERVIEW: an exception class
public:
	emptyList() {}
};

template <typename T>
class Dlist {
	// OVERVIEW: contains a double-ended list of Objects
public:
	// Operational methods
	bool isEmpty() const;
	// EFFECTS: returns true if list is empty, false otherwise
	void insertFront(T* o);
	// MODIFIES this
	// EFFECTS inserts o at the front of the list
	void insertBack(T* o);
	// MODIFIES this
	// EFFECTS inserts o at the back of the list
	T* removeFront();
	// MODIFIES this
	// EFFECTS removes and returns first object from non-empty list
	// throws an instance of emptyList if empty
	T* removeBack();
	// MODIFIES this
	// EFFECTS removes and returns last object from non-empty list
	// throws an instance of emptyList if empty
	// Maintenance methods
	Dlist(); // constructor
	Dlist(const Dlist& l); // copy constructor
	Dlist& operator=(const Dlist& l); // assignment
	~Dlist(); // destructor
private:
	// A private type
	struct node {
		node* next;
		node* prev;
		T* o;
	};
	node* first; // The pointer to the first node (NULL if none)
	node* last; // The pointer to the last node (NULL if none)
	// Utility methods
	void makeEmpty();
	// EFFECT: called by constructors to establish empty list invariant
	void removeAll();
	// EFFECT: called by destructor/operator= to remove and destroy all list elements
	void copyAll(const Dlist& l);
	// EFFECT: called by copy constructor/operator= to copy elements
	// from a source instance l to this instance
};
template<class T>
void Dlist<T>::insertFront(T* o)
{
	node* temp = new node();
	temp->o = o;
	temp->prev = nullptr;
	temp->next = first;
	if (first)
		first->prev = temp;
	else
		last = temp;
	first = temp;
}
template<class T>
void Dlist<T>::insertBack(T* o) {
	node* temp = new node;
	temp->o = o;
	temp->next = nullptr;
	temp->prev = last;
	if (last)
		last->next = temp;
	else
		first = temp;
	last = temp;
}
template<class T>
bool Dlist<T>::isEmpty() const {
	return first == nullptr;
}
template<class T>
T* Dlist<T>::removeFront() {
	if (first) {
		node* temp = first;
		first = first->next;
		if (first)
			first->prev = nullptr;
		else {
			first = nullptr;
			last = nullptr;
		}
		return temp->o;
	}
	else {
		try {
			emptyList* e = new emptyList();
			throw(e);
		}
		catch (emptyList * that) {
			cout << "Not enough operands" << endl;
		}
		return nullptr;
	}
}
template<class T>
T* Dlist<T>::removeBack() {
	if (last) {
		node* temp = last;
		last = last->prev;
		if (last)
			last->next = nullptr;
		else {
			first = nullptr;
			last = nullptr;
		}
		return temp->o;
	}
	else
	{
		try {
			emptyList* e = new emptyList();
			throw(e);
		}
		catch (emptyList * that) {
			cout << "Not enough operands" << endl;
		}
		return nullptr;
	}
}
template<class T>
Dlist<T>::Dlist() {
	makeEmpty();
}
template<class T>
Dlist<T>::Dlist(const Dlist& l) {
	copyAll(l);
}
template<class T>
Dlist<T>& Dlist<T>::operator=(const Dlist& l) // assignment
{
	removeAll();
	copyAll(l);
	return *this;
}
template<class T>
Dlist<T>::~Dlist() {
	removeAll();
}
template<class T>
void Dlist<T>::makeEmpty() {
	first = nullptr;
	last = nullptr;
}
template<class T>
void Dlist<T>::removeAll() {
	node* p = first;
	while (p) {
		node* temp = p;
		p = p->next;
		delete temp;
	}
}
template<class T>
void Dlist<T>::copyAll(const Dlist& l) {
	if (l.first) {
		//makeEmpty();
		node* p = l.first;
		node* q = new node;
		first = q;
		node* pq = nullptr;
		while (p) {
			q->o = p->o;
			q->prev = pq;
			pq = q;
			if (!p->next)
			{
				last = q;
				q->next = nullptr;
				break;
			}
			q->next = new node;
			q = q->next;
			p = p->next;
		}
	}
}
#endif /* __DLIST_H__ */

main.cpp

#include<iostream>
#include<fstream>
#include<vector>
#include"Dlist.h"
using namespace std;
#define MAX 100000 
struct tele
{
	int timestamp, status, duration, id;
	string name;
};
int n;
bool vis[MAX];//vis记录时间片
Dlist<tele>* list = new Dlist<tele>;
void infile() {//文件数据读取
	ifstream inFile;
	inFile.open("simple.txt");
	if (inFile.fail())
		cout << "simple.txt doesn't exist" << endl;
	else
	{
		int i = 0;
		inFile >> n;
		while (!inFile.eof())
		{
			tele* temp = new tele;
			inFile >> temp->timestamp >> temp->name >> temp->status >> temp->duration;
			temp->id = i++;
			list->insertBack(temp);//倒插入队列
		}
		inFile.close();
	}
}
int main()
{
	memset(vis, 0, sizeof(vis));
	infile();
	int cnt = 0, snum = n;//cnt为当前时间,snum为未处理电话
	while (!list->isEmpty()) {//队列不空则继续循环
		Dlist<tele>* ltemp = new Dlist<tele>;
		cout << "Starting tick #" << cnt << endl;
		int temptime = 0, tempi = 0, tempid = 0, minn = MAX, tempsort = 0;
		do{
			tempi++;//限制do-while循环不能超过未处理电话数目
			tele* t = new tele;
			t = list->removeFront();//为遍历只能删除,后面会再加回去
			if (cnt == t->timestamp)//当前时间节点来电
				cout << "Call from " << t->name << " a Level" << t->status << " member" << endl;
			if (t->status < minn)//寻找优先级最高的来电
			{
				tempid = t->id;//id记录下来
				minn = t->status;
			}
			ltemp->insertFront(t);//把刚刚删除的节点放入ltemp队列中,等待插回队列
			temptime = t->timestamp;//时间限制循环
		} while (temptime <= cnt && tempi < snum);
		while (!ltemp->isEmpty()) {
			tele* temp = new tele();
			temp = ltemp->removeFront();
			if (temp->id == tempid && !vis[cnt])//如果当前节点没有正在处理的电话,则处理优先级最高的来电(不用插回队列)
			{
				--snum;
				for (int count = 0; count < temp->duration; count++)//来电持续时长
					vis[temp->timestamp + count] = 1;
				cout << "Answering call from " << temp->name << endl;
			}
			else 
				list->insertFront(temp);
		}
		cnt++;//时间向前走
	}
	cout << "Starting tick #" << cnt << endl;//最后输出一次
	return 0;
}


标签:node,last,temp,Dlist,用户,C++,离散,模拟,first
From: https://blog.51cto.com/u_16165815/6520504

相关文章

  • 逆波兰式求值(C++_模拟)
    题目       将中缀表达式翻译成后缀表达式(逆波兰表达式)时,可以去掉中缀表达式中出现的括号,简化表达式。如中缀表达式“(2+3)6”被转成后缀表达式“23+6”后,可以借助于栈对表达式求值,完成运算。规则大致如下:       遇到操作数,则入栈;       遇到二元运算符,则......
  • P1203 [USACO1.1]坏掉的项链Broken Necklace(C++_模拟_暴力枚举_优化)
    题目描述你有一条由n个红色的,白色的,或蓝色的珠子组成的项链,珠子是随意安排的。这里是n=29的两个例子:第一和第二个珠子在图片中已经被作记号。图片A中的项链可以用下面的字符串表示:brbrrrbbbrrrrrbrrbbrbbbbrrrrb假如你要在一些点打破项链,展开成一条直线,然后从一端开始收集......
  • P1582 倒水(C++_数论_进制)
    题目描述一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水。接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子。每次他选择两个当前含水量相同的瓶子,把一个瓶子的水全部倒进另一个里,然后把空瓶丢弃。(不能丢弃有水的瓶子)显然在某些情况下CC无法达到目标,比......
  • P1478 陶陶摘苹果(升级版)(C++_贪心)
    题目描述又是一年秋季时,陶陶家的苹果树结了n个果子。陶陶又跑去摘苹果,这次他有一个a公分的椅子。当他手够不着时,他会站到椅子上再试试。这次与NOIp2005普及组第一题不同的是:陶陶之前搬凳子,力气只剩下s了。当然,每次摘苹果时都要用一定的力气。陶陶想知道在s<0s<0之前最多......
  • CCF_201612-4 压缩编码(C++_区间DP)
    问题描述       给定一段文字,已知单词a1,a2,…,an出现的频率分别t1,t2,…,tn。可以用01串给这些单词编码,即将每个单词与一个01串对应,使得任何一个单词的编码(对应的01串)不是另一个单词编码的前缀,这种编码称为前缀码。使用前缀码编码一段文字是指将这段文字中的每......
  • PAT_Advanced Level_1078 Hashing (25分)(C++_Hush_平方探测法)
    Thetaskofthisproblemissimple:insertasequenceofdistinctpositiveintegersintoahashtable,andoutputthepositionsoftheinputnumbers.ThehashfunctionisdefinedtobeH(key)=key%TSizewhereTSizeisthemaximumsizeofthehashtable.Qu......
  • 数据结构代码整理_队列Queue(C++)
    所谓队列,就是先进先出规则的实现。基于链表实现main.cpp#include<iostream>#include"Queue.h"usingnamespacestd;intmain(){ Queueq; q.append(1); q.append(2); Queue_entrya; q.retrieve(a); cout<<a<<""<<q.empty(); return......
  • PTA_乙级_1001 害死人不偿命的(3n+1)猜想 (C++_数论)
    卡拉兹(Callatz)猜想:对任何一个正整数n,如果它是偶数,那么把它砍掉一半;如果它是奇数,那么把(3n+1)砍掉一半。这样一直反复砍下去,最后一定在某一步得到n=1。卡拉兹在1950年的世界数学家大会上公布了这个猜想,传说当时耶鲁大学师生齐动员,拼命想证明这个貌似很傻很天真的命题,结果闹......
  • 数据结构代码整理_栈Stack(C++)
           所谓栈,就是先进后出规则的实现,这种数据结构在DFS等算法体现的较为明显,因为课程要求不得不进行各种数据结构实现代码整理,就发出来与大家分享。下面有两种实现方法一个是基于数组实现的,另一个是基于链表实现的。基于数组实现源码main.cpp//main.cpp:定义控制台应用程......
  • C++使用ranges库解析INI文件
    C++使用ranges库解析INI文件引言C++20引入了<ranges>头文件,C++23对其进行了完善,本文将使用该头文件提供的adaptor编写一个简单的ini解析器。ini文件格式介绍一般的ini文件由section和entry部分,比如[section]key=value;Thisisentry.section和entry均独占一行,其中sectio......