PAT甲组1014.Waiting in Line思路与注意点--补充《算法笔记》

A1014

题目链接

个人思路

个人思路与答案略有不同,要明确每个客户的结束时间等于当前窗口的结束时间+服务时间。因此窗口结束时间windowEnd[]为了计算每个客户的结束时间;窗口队首客户的结束时间windowFront[]为了在队满时寻找最早结束的窗口进行入队

  • 首先初始化每一个窗口第一批客户,更新窗口的结束时间和队首客户的结束时间
  • 随后对其余客户遍历
    • 先遍历窗口,队满时记录最早结束窗口的id,队不满时记录人最少的窗口id,同时要注意编号最小
    • 队不满时,入队,更新数据
    • 对满时,出队,入队,更新数据

个人思路代码

采用deque容器,便于遍历和队首队尾插入删除
不知道哪里有问题,个人思路的代码有一个测试点未通过

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3fffffff;
int N, M, K, Q;
struct Customer{
	int endTime;
}customers[1005];
//处理时间,窗口结束时间,队首客户的结束时间 
int serveTime[1005], windowEnd[25], windowFront[25];
deque<Customer>windowLine[25];//窗口队伍 
int open = 8 * 60, close = 17 * 60;
//结束时间m,服务时间d 
void display(int m, int d)//输出结束时间 
{
	if(m - d < close)
	{
		int hh = m / 60;
		int mm = m % 60;
		printf("%02d:%02d\n", hh, mm);
	}
	else//结束时间超过17:00输出sorry 
		printf("Sorry\n");
}
int main(int argc, char *argv[]) {
	scanf("%d%d%d%d", &N, &M, &K, &Q);
	//下标全从1开始 
	for(int i = 1; i <= K; ++i)
	{
		scanf("%d", &serveTime[i]);
	}

	//初始化每个窗口的第一批N个客户 
	for(int i = 1; i <= N; ++i)
	{
		windowEnd[i] = open + serveTime[i];
		customers[i].endTime = windowEnd[i];
		windowLine[i].push_back(customers[i]);
		windowFront[i] = customers[i].endTime;
	}
	//从N + 1到 K客户 
	for(int i = N + 1; i <= K; ++i)
	{
		//遍历窗口,找出人数最少的窗口winID,临时记录所有队满中结束最早的endTimeID 
		int winID = -1, minLine = inf, minEndTime = inf, endTimeID = -1;
		for(int j = 1; j <= N; ++j)
		{
			if(windowLine[j].size() == M)//当前队满 
			{ 
				if(windowFront[j] < minEndTime)//找结束最早的窗口 
				{
					minEndTime = windowFront[j];
					endTimeID = j;
				}
				continue;
			} 
			if(windowLine[j].size() < minLine)//找人最少队伍,且序号最小的 
			{
				minLine = windowLine[j].size();
				winID = j;
			}
		}
		if(winID != -1)//队不满 
		{
			customers[i].endTime = windowEnd[winID] + serveTime[i];
			windowLine[winID].push_back(customers[i]);//排队 
			windowEnd[winID] += serveTime[i];
		}
		else//说明所有队满,找最早结束的窗口 ,考虑出队 
		{
			//入队,一直是队满状态 
			winID = endTimeID;
			windowLine[winID].pop_front();//队首出队 
			windowEnd[winID] = windowFront[winID] = windowLine[winID][0].endTime;//更新 
			customers[i].endTime = windowEnd[winID] + serveTime[i];
			windowLine[winID].push_back(customers[i]);	
		} 		
	}
	for(int i = 1; i <= Q; ++i)
	{
		int query;
		scanf("%d", &query);
		display(customers[query].endTime, serveTime[query]);
	}
	return 0;
}

在这里插入图片描述

本题思路

  • 先将队伍循环填满,此方法可保证每次找到人数最少,编号最小的队伍——很值得借鉴
  • 17:00前开始服务,17:00后服务结束,也是有效的数据
  • 对窗口采用结构体还是比较明智的,没有个人思路中数据结构太多显得有点乱

AC代码

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3fffffff;
const int maxn = 1005;
int N, M, K, Q;
int serveTime[maxn], customer[maxn];//处理时间,客户结束时间 
int open = 8 * 60, close = 17 * 60;
struct Window{
	int frontTime = open;//队首客户结束时间 
	int endTime = open;//窗口结束时间 
	queue<int> q;
}windows[25];//初始化,由于是结构体数组,需要初始化 
//结束时间m,服务时间d 
void display(int m, int d)//输出结束时间 
{
	if(m - d < close)
	{
		int hh = m / 60;
		int mm = m % 60;
		printf("%02d:%02d\n", hh, mm);
	}
	else//结束时间超过17:00输出sorry 
		printf("Sorry\n");
}

int main(int argc, char *argv[]) {
	scanf("%d%d%d%d", &N, &M, &K, &Q);
	//下标全从0开始 
	for(int i = 0; i < K; ++i)
	{
		scanf("%d", &serveTime[i]);
	}
	
	
	int index = 0;//当前为入队的客户下标
	//由于取模,窗口下标从0开始 
	for(int i = 0; i < min(N * M, K); ++i)//先把所有队列填满,如果K较小,会出现队列不满的情况 
	{
		int winID = index % N;
		windows[winID].q.push(index);//客户入队
		windows[winID].endTime += serveTime[index];
		if(index < N)//判断队首客户 
			windows[winID].frontTime =  windows[winID].endTime;
		customer[index] = windows[winID].endTime;
		++index;
	} 
	//所有队满,仍有尚未入队的客户 
	for(; index < K; ++index)
	{
		int winID = -1, minFrontTime = inf;
		for(int i = 0; i < N; ++i)//找结束最早的队伍 
		{
			if(windows[i].frontTime < minFrontTime)
			{
				winID = i;
				minFrontTime = windows[i].frontTime;
			}
		}
		windows[winID].q.pop();//队首出队  
		int cusID = windows[winID].q.front();
		windows[winID].frontTime = customer[cusID];//更新队首结束时间 
		windows[winID].q.push(index);//入队
		windows[winID].endTime += serveTime[index];//更新窗口结束时间
		customer[index] = windows[winID].endTime;//
	}
	
	
	for(int i = 1; i <= Q; ++i)
	{
		int query;
		scanf("%d", &query);
		display(customer[query - 1], serveTime[query - 1]);//下标从0开始 
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值