PAT 1017. Queueing at Bank (25)

#include<iostream>

#include<cstdio>

#include<string>

#include<cstring>

#include<queue>

#include<vector>

#include<cmath>

#include<iomanip>

#include<algorithm>

using namespace std;



const int MAX_N = 10000+5;

const int MAX_WIN = 100+5;

const int OFF_TIME = 9*60*60;

const int ONE_HOUR = 60*60;



struct Customer

{

	int iArrTime;  //到达的时间

	int iProTime;  //处理的时间

	int iWaitTime; //等待的时间

	bool isServed;//是否被处理

};

Customer arrCus[MAX_N];



struct Windows

{

	int iAvaiTime;//窗口available的时间

	

};

Windows arrWins[MAX_WIN];



//按到达时间进行排序

bool lessCmp(Customer cus1, Customer cus2)

{

	return cus1.iArrTime < cus2.iArrTime;

}



//将07:55:00形式的时间转换为相对08:00的时间,单位:秒。

//如果早于8点,则返回负数。

int getRelTime(char *chTime)

{

	int iRes;

	int h = (chTime[0] - '0')*10 + chTime[1]-'0';

	int m = (chTime[3] - '0')*10 + chTime[4]-'0';

	int s = (chTime[6] - '0')*10 + chTime[7]-'0';

	int iEight = 8*60*60;

	int iNow = (h*60 + m)*60 + s;

	iRes = iNow - iEight;

	return iRes;

}



void initData(int N,int K)

{

	int i,j;

	for(i=0; i<N; i++)

	{

		arrCus[i].iArrTime = 0;

		arrCus[i].iProTime = 0;

		arrCus[i].iWaitTime = 0;

		arrCus[i].isServed = true;

	}

	for(j=0; j<K; j++)

	{

		arrWins[j].iAvaiTime = 0;		

	}

}





//得到一个空闲的窗口,遍历K个窗口,找到窗口available最早的时间

int getAnFreeWin(int K)

{

	int iAvaTimeMin = arrWins[0].iAvaiTime;

	int iWinIndex = 0;

	for(int i=1; i<K; i++)

		if(arrWins[i].iAvaiTime < iAvaTimeMin)

		{

			iAvaTimeMin = arrWins[i].iAvaiTime;

			iWinIndex = i;

		}

	return iWinIndex;

}



int max(int a,int b)

{

	return a>b?a:b;

}



//窗口iWinId处理完一个客户后,需要更新窗口available最早的时间

void updateWinsInfo(int iWinId,int iCusId)

{

	int iCurTime = max(arrWins[iWinId].iAvaiTime,arrCus[iCusId].iArrTime);



	if(arrCus[iCusId].iProTime <= ONE_HOUR)//处理的时间不能超过一个小时

		arrWins[iWinId].iAvaiTime =iCurTime + arrCus[iCusId].iProTime;

	else

		arrWins[iWinId].iAvaiTime =iCurTime + ONE_HOUR;

}



//将iCusId客户放到窗口iWinId进行处理

void processAnCus(int iWinId, int iCusId)

{

	//如果在客户到之前就有窗口空闲,或者在下班以后窗口才空闲,则等待时间为0



	if(arrWins[iWinId].iAvaiTime == 0) //开始就空闲的窗口

	{

		if(arrCus[iCusId].iArrTime < 0)

			arrCus[iCusId].iWaitTime = abs(arrCus[iCusId].iArrTime);

		else if(arrCus[iCusId].iArrTime > OFF_TIME)

		{

			arrCus[iCusId].iWaitTime = 0;

			arrCus[iCusId].isServed = false;

		}

		else //没有等待,直接到窗口。

			arrCus[iCusId].iWaitTime = 0;

	}

	else//处理过客户的窗口

	{

		//if(arrWins[iWinId].iAvaiTime > OFF_TIME || arrCus[iCusId].iArrTime > OFF_TIME)//下班后的将不被处理

                if(arrCus[iCusId].iArrTime > OFF_TIME)//之前一直有个case过不了,发现是题目意思理解错了。。

                //即,客户只要在17:00之前到达银行,那么即使窗口的avaliable时间在17:00以后,那银行还是需要给

                //客户进行服务的

		{

			arrCus[iCusId].iWaitTime = 0;

			arrCus[iCusId].isServed = false;

		}

		else

		{

			if(arrWins[iWinId].iAvaiTime <= arrCus[iCusId].iArrTime)

				arrCus[iCusId].iWaitTime = 0;

			else

				arrCus[iCusId].iWaitTime = arrWins[iWinId].iAvaiTime - arrCus[iCusId].iArrTime;

		}

	}

		

	updateWinsInfo(iWinId,iCusId);

}



//获得所有客户的等待时间

double getAverageWaitTime(int N)

{

	int iSum = 0;

	int iCount = 0;

	for(int i=0; i<N; i++)

		if(arrCus[i].isServed)

		{

			iSum += arrCus[i].iWaitTime;

			iCount++;

		}

	if(iCount == 0)

		return 0;

	else

		return (double(iSum)/60)/iCount;

}



//对在等待队列上的客户进行处理

void process(int N, int K)

{

	sort(arrCus,arrCus+N,lessCmp);

	int iCusId = 0;

	while(iCusId < N)

	{

		int iFreeWinId = getAnFreeWin(K);

		processAnCus(iFreeWinId, iCusId);

		iCusId++;

	}

}



int main()

{	

	int N,K,i,j,iProTime;

	char chArrTime[10];

	scanf("%d %d",&N,&K);

	initData(N,K);

	for(i=0; i<N; i++)

	{

		scanf("%s",chArrTime);

		int iRelTime = getRelTime(chArrTime);

		arrCus[i].iArrTime = iRelTime;

		scanf("%d",&iProTime);

		arrCus[i].iProTime = iProTime*60;

	}

	process(N, K);

	cout<<fixed<<setprecision(1)<<getAverageWaitTime(N)<<endl;

	return 0;

}

  

你可能感兴趣的:(Queue)