궤도

[EPPER] 12회 10번 본문

💻 현생/⛓ 알고리즘

[EPPER] 12회 10번

영이오 2020. 10. 9. 18:20

문제

 


풀이

 

어렵다. 큐를 이용하라는데 c++도 아닌 마당에 큐를 하나하나 구현하고 싶진 않아서 그냥 내맘대로 구현했다. 그리고 이게 더 편한 것 같다. 큐로 구현하려면 내가 쓴 논리 구조랑 아주 다른 방법으로 해야할 듯하다.

 

factory 구조체를 만들었다. 이 구조체에는 공정별 소요 시간과 선행되어야 하는 공정이 있는지 있다면 그 선행 공정의 개수그 종류를 저장하고 마지막으로 해당 공정이 완료된 공정인지 확인하는 bool 변수를 넣었다.

 

먼저 공정별 소요 시간을 저장하며 선행 공정의 수인 b_num을 0으로 초기화 하고 isDone도 false로 초기화한다. 그리고 나서 선행공정의 관계를 입력받아 저장한다. 이 부분 코드가 좀 복잡해보일 수 있지만 어려운 부분은 아니다. 마지막으로 목표 공정 번호를 저장한다.

 

입력을 다 받았으니 while loop를 돌린다. 반복문을 빠져나올 조건은 '목표 공정이 완료될 것'이다. 일단 모든 공정에 대해 이번에 해당 공정을 할 수 있는지 isPos 함수로 확인한다. 특정 공정을 이번에 할 수 있는 조건은 다음과 같다.

 

1. 아직 한 일이 아닐 것

2. 선행 공정이 없을 것

3. 선행 공정이 있다면, 그 모든 선행 공정을 이미 한 상태일 것

 

해당 조건에 맞춰서 함수를 작성한다. isPos 함수를 통해 이번에 할 수 있는 공정이라는 것을 확인하면 각각의 공정 index와 소요 시간을 check_arr와 temp_arr에 저장한다. 왜 바로바로 반영하지 않고 굳이 저장해뒀다가 한번에 반영하는 이유가 궁금할 수 있다. 그 이유를 위 입력 예시로 설명하도록 하겠다.

공정 A는 지금 당장 할 수 있는 일이다. 그래서 공정 A의 isDone을 바로 true로 바꿨다. 순서대로 모든 배열을 탐색할테니 그 뒤로 B, C, D를 탐색할 것이다. 그리고 A의 isDone이 true이니 공정 B, C도 지금 당장 할 수 있는 일로 체크될 것이고 연쇄적으로 공정 D도 당장 할 수 있는 일로 체크될 것이다. 이런 문제를 막고자 배열을 탐색 한 뒤에 한번에 결과를 반영하는 것이다.

아무튼 이렇게 배열을 돌고나면 check_arr과 temp_arr에는 지금 당장 동시에 진행할 수 있는 공정이 쌓일 것이다. 이 중에서 가장 오래 걸리는 일만 끝나면 바로 다음 일을 할 수 있으니 가장 긴 공정만 sum에 더해주고, 이제서야 해당 공정들을 다 true로 체크한다.

 

check_arr, temp_arr의 회차별 원소들을 정리했다.


소스코드

 

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct factory{ //소요시간, 선행공정, 작업했는지 확인
	int dur;
	int b_num;
	int before[101];
	bool isDone;
}factory;
factory task[101];

bool isPos(factory t) {
	bool allDone = true;
	if (t.isDone) //이미 한 일이면 또 할 이유가 없음
		return false;
	if (t.b_num == 0) //선행되어야 하는 일이 없으면 바로 할 수 있음
		return true;
	for (int i = 0; i < t.b_num; i++) { //선행되어야 하는 모든 일들을 이미 했다면 바로 할 수 있음
		if (task[t.before[i]].isDone == false)
			allDone = false;
	}
	if (allDone)
		return true;
	else
		return false;
}

int main() {
	int N, R;
	int temp_b, temp_a;
	int temp_arr[101];
	int check_arr[101];
	int sum = 0;
	int obj_t;

	scanf("%d %d", &N, &R);
	for (int i = 1; i <= N; i++) { //구조체에 값 채움
		scanf("%d", &task[i].dur);
		task[i].b_num = 0;
		task[i].isDone = false;
	}
	for (int i = 0; i < R; i++) {
		scanf("%d %d", &temp_b, &temp_a);
		task[temp_a].before[task[temp_a].b_num++] = temp_b; //선행되어야 하는 공정을 입력
	}
	scanf("%d", &obj_t); //마지막 공정
	while (true) {
		int arr_cnt = 0;
		if (task[obj_t].isDone==true) //마지막 공정까지 했으면 반복문 빠져나옴
			break;
		for (int i = 1; i <= N; i++) { //모든 공정에 대해 이번에 할 수 있는 일인지 확인
			if (isPos(task[i])) {
				check_arr[arr_cnt] = i; //나중에 isDone을 한번에 true로 바꾸기 위해 배열에 넣어둠
				temp_arr[arr_cnt++] = task[i].dur; //걸리는 시간을 저장하는 배열
			}
		}
		int max_task = temp_arr[0];
		for (int i = 1; i < arr_cnt; i++) { //가장 오래 걸리는 일을 체크
			if (max_task < temp_arr[i])
				max_task = temp_arr[i];
		}
		sum += max_task; //sum에 가장 오래 걸리는 일만 더해줌
		for (int i = 0; i < arr_cnt; i++) //일을 다 했으므로 isDone을 true로 바꿔줌
			task[check_arr[i]].isDone = true;
	}
	printf("%d", sum);
}
Comments