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;
}

  

posted @ 2012-12-11 18:23  Frank@609  Views(843)  Comments(0Edit  收藏  举报