본문 바로가기

알고리즘/SWEA

2477

static int N, M, K, A, B;
static int reception_time[10];
static int repair_time[10];
static queue<int> customer_time;

static int reception_desk[10][2];
static int repair_desk[10][2];
static bool customer_table[1001];
static queue<int> wq; //wait queue

static bool is_end()
{
	bool end = true;

	for (int i = 1; i <= N; i++)
	{
		if (reception_desk[i][0]) //손님이 있는 접수 창구가 있으면,
		{
			end = false; //실패,
			break;
		}
	}

	//모든 손님들이 정비까지 끝냈거나, 일부 손님만 정비 창구에 있는 경우에만 true,
	return end & customer_time.empty() & wq.empty();
}

static int solution(void)
{
	int last_time = 0, ret = 0;
	
	scanf("%d %d %d %d %d", &N, &M, &K, &A, &B);
	for (int i = 1; i <= N; i++)
		scanf("%d", &reception_time[i]);
	for (int i = 1; i <= M; i++)
		scanf("%d", &repair_time[i]);
	for (int cnt = 0; cnt < K; cnt++)
	{
		scanf("%d", &last_time);
		customer_time.push(last_time);
	}

	//시간에 흐름에 따라,
	for (int t = 0, cus = 1; !is_end(); t++)
	{
		//접수 창구 부터,
		for (int i = 1; i <= N; i++)
		{
			if (!reception_desk[i][0]) //고객을 할당 할 수 있다면,
			{
            			//해당 시간 대에 존재 할 수 있는 고객이라면,
				if (customer_time.size() && customer_time.front() <= t) 
				{
					reception_desk[i][0] = reception_time[i]; //타이머 설정,
					reception_desk[i][1] = cus; //고객 번호 등록,
					customer_time.pop(); //해당 고객 제거,

					if (i == A) //특정 접수 창구를 이용한 경우,
						customer_table[cus] = true;

					cus += 1; //다음 고객 번호,
				}
			}
			else //고객이 할당 된 상태
			{
				reception_desk[i][0] -= 1; //타이머 동작,

				if (!reception_desk[i][0]) //해당 창구의 접수가 끝남,
				{
					wq.push(reception_desk[i][1]); //정비 창구 큐에 등록,
					i -= 1; //***해당 접수 창구에 고객을 할당 할 수 있는지 확인 하기 위해,***
				}
			}
		}

		//정비 창구 차례,
		for (int i = 1; i <= M; i++)
		{
			if (!repair_desk[i][0]) //고객을 할당 할 수 있다면,
			{
				if (wq.size()) //접수를 끝낸 고객이 있다면,
				{
					repair_desk[i][0] = repair_time[i]; //타이머 설정,
					repair_desk[i][1] = wq.front(); //고객 번호 등록,

					if (i == B) //특정 정비 창구를 이용한 경우
					{
						customer_table[wq.front()] &= true; //현재 값이 true여야 true가 됨,
                        			//특정 접수/정비 창구 모두 이용한 경우,
						if (customer_table[wq.front()]) 
							ret += wq.front();
					}

					wq.pop(); //해당 고객 제거,
				}
			}
			else //고객이 할당 된 상태,
			{
				repair_desk[i][0] -= 1; //타이머 동작,

				if (!repair_desk[i][0]) //정비가 끝난 경우,
					i -= 1; //***다음 고객을 할당 시킬 준비,***
			}
		}
	}

	memset(repair_desk, 0, sizeof(repair_desk));
	memset(reception_desk, 0, sizeof(reception_desk));
	memset(customer_table, false, sizeof(customer_table));

	if (!ret)
		ret = -1;

	return ret;
}

예전에 풀었던 문제 중 우편함이랑 비슷한 느낌의 문제였다.

그래서 시간의 흐름을 제일 큰 for문으로 하고, 그 안에서 시간이 흐름에 따라 각 창구에 고객을 할당하는 방식으로

코드를 작성하였다.

 

고객은 도착한 순서대로 먼저 접수를 할 수 있기 때문에, 큐를 사용하여 이에 대한 것을 구현 하였다.

 

그리고 코드 대부분의 주석을 작성하였고, 이를 토대로 이해하면 되는데,

주의할 만한 부분이 있다면, 이는 전체 반복의 종료 조건과, 접수, 정비 창구의 타이머가 다되어 할당된 고객을 처리하였을 때가 있다.

 

위 코드는 다음과 같은 구조로 동작하는데,

반복의 종료 조건은 접수 큐에 있던 모든 고객이 접수를 끝낸 후,

정비 큐에 있는 모든 고객이 정비를 받는 상태가 되는 순간이다.

 

참고로 정비 창구에 고객을 할당하는 스케줄링의 조건 중 다음과 같은 조건이 있다.

"두 명 이상의 고객들이 접수 창구에서 동시에 접수를 완료하고 정비 창구로 이동한 경우, 이용했던 접수 창구번호가 작은 고객이 우선한다."

사실 이 부분을 어찌 처리할지 고민하였는데,

위 코드를 보면 인덱스가 작은 창구에서 접수한 고객부터 정비 큐에 큐잉되는 구조이므로, 위와 같은 코드 구조에서는 큰 신경을 쓸 필요가 없는 문제였다.

 

다음은 타이머가 종료되어 할당 받은 고객에 서비스를 마친 순간에 대한 처리이다.

각 창구의 반복문을 보면 인덱스가 순차적으로 증가하는 구조이다.

그래서 1번 창구에서 서비스를 마치고 그 인덱스의 아무런 처리를 해주지 않으면 해당 창구에 고객을 할당해줄 수 있지만, 코드 구조 상 할당해 줄 수 없게된다.

그래서 인덱스 값을 하나 감소시켜, 다음 반복이 실행되기전 해당 위치의 창구에 대해 다시 검사하게 하는 것이다.

'알고리즘 > SWEA' 카테고리의 다른 글

8458  (0) 2021.11.04
8500  (0) 2021.11.04
2105  (0) 2021.11.04
4014  (0) 2021.11.04
2115  (0) 2021.11.04