Algorithm/기타(기업등)
[EPPER/13회 9번]N개의 작업공정(상-4)
IagreeBUT
2021. 3. 18. 19:34
728x90
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#define MAX 101
using namespace std;
/*
공정끼리 선후관계가 존재하고, 선후관계에 따라 공정을 처리해한다.
선후관계가 있는 것은 보통 방향그래프로 나타낼 수 있고, 이는 위상정렬로 처리가능하다.
위상정렬 알고리즘?
선수과목 등 선행 관계가 있는 자료구조를 정렬하는 알고리즘
사이클이 없는 방향그래프에서 선행순서를 위배하지 않으면서 정점을 순서대로 정렬함
방향그래프에서 <u,v>가 있다면 u가 v에 대해 선행됨
위상정렬 방법
1. 진입차수가 0인 정점을 큐에 삽입함
2. 큐에서 원소를 꺼내 에지를 제거한 후 진입 차수를 재계산
3. 모든 정점이 제거될때 까지 1~2를 반복함
4. 모든 원소를 방문하기 전 진입 차수가 0인 것이 없으면, 사이클이 존재해서 해가 없음
*/
int adj[MAX][MAX] = {0,};
int indegree[MAX] = {0,};
int timeA[MAX] = {0,};
int solution(int n[], int r[][100], int goal, int N, int R){
queue<int> q;
//선행관계를 파악하기 위한 배열을 초기화
//u->v 인 경우 adj[u][v] = 1을 대입해둠
for(int i=0; i<R; i++){
//입력받은 연관관계 [0] 선행 [1] 후행
int u = r[i][0];
int v = r[i][1];
adj[u][v] = 1;
//선행해야하는 기기가 몇개나 있는지에 대한 배열 업데이트
indegree[v]++;
}
//선행해야하는 공정이 없는 경우 q에 넣고 시간을 업데이트
for(int i=1; i<=N; i++){
if(indegree[i]==0){ //공정이 없는 경우
timeA[i]= n[i-1]; //해당하는 시간을 대입( 실제로 index가 1씩 차이나서 -1있음 )
q.push(i); //큐에 넣음
}
}
while(!q.empty()){ //큐가 빈 큐가될 떄 까지 진행
int p=q.front(); // 맨 앞에있는 것을 빼내기
q.pop();
for(int i=1; i<=N; i++){
if(adj[p][i] == 1){ //빼낸것을 선행으로 가지는 공정이 있으면
timeA[i] = max(timeA[i], timeA[p] + n[i-1]); //현재 , 현재 + 지금 공정진행 중 최대값으로 변경
indegree[i]--; // 하나 줄여줌
if(indegree[i] == 0) q.push(i); //공정이 한개 빠져서 0이된 공정이 있다면 큐에 다시넣음
}
}
}
return timeA[goal];
}
int main(){
int N;
int R;
int n[100]={0} ;
int r[100][100]={0};
int goal;
cin>>N>>R;
for(int i=0;i<N;i++) {
cin>>n[i];
}
for(int k=0;k<R;k++) {
for(int j=0;j<2;j++) {
cin>>r[k][j];
}
}
cin>>goal;
cout<<solution(n,r,goal,N,R);
}
벡터로 바꿈
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define MAX 101
using namespace std;
/*
공정끼리 선후관계가 존재하고, 선후관계에 따라 공정을 처리해한다.
선후관계가 있는 것은 보통 방향그래프로 나타낼 수 있고, 이는 위상정렬로 처리가능하다.
위상정렬 알고리즘?
선수과목 등 선행 관계가 있는 자료구조를 정렬하는 알고리즘
사이클이 없는 방향그래프에서 선행순서를 위배하지 않으면서 정점을 순서대로 정렬함
방향그래프에서 <u,v>가 있다면 u가 v에 대해 선행됨
위상정렬 방법
1. 진입차수가 0인 정점을 큐에 삽입함
2. 큐에서 원소를 꺼내 에지를 제거한 후 진입 차수를 재계산
3. 모든 정점이 제거될때 까지 1~2를 반복함
4. 모든 원소를 방문하기 전 진입 차수가 0인 것이 없으면, 사이클이 존재해서 해가 없음
*/
int adj[MAX][MAX] = {0,}; //선행관계를 저장한 2차배열 adj[u][v] == 1이면, u->v (u가 v에 대해 선행 )
int indegree[MAX] = {0,}; //배열index에 해당하는 공정이 몇개나 선행 공정을 가졌는지 저장하는 배열
int timeA[MAX] = {0,}; // 공정이 index인 애의 최소 소요시간
int solution(vector<int> n, vector<vector<int>>r, int goal, int N, int R)
{
queue<int> q;
//adj배열을 초기화
for(int i=0; i<R; i++){
int u = r[i][0]; //r배열에 처음이 선행
int v = r[i][1]; //r배열 다음이 후행
adj[u][v] = 1; //u->v관계에 1 넣어놓기
indegree[v]++;//후행index에서 ++
}
//공정을 돌리면서 선행 공정이 없으면 q에 집어넣음
for(int i=1; i<=N; i++){
if(indegree[i]==0){ // 선행공정이 없음
timeA[i]= n[i-1]; // 시간을 저장하는데 n : i-1이어야함 (idex때문에)
q.push(i); //큐에 넣기
}
}
//이제 큐를 이용
while(!q.empty()){
//빼오고 뺀거 삭제
int p=q.front();
q.pop();
//모든 공정확인
for(int i=1; i<=N; i++){
if(adj[p][i] == 1){ // 뺸거를 선행하는 무언가가 있다면
timeA[i] = max(timeA[i], timeA[p] + n[i-1]); //시간을 갱신시켜줌
indegree[i]--;//그리고 그친구는 1을 잃음
if(indegree[i] == 0) q.push(i); //뺴서 0이되었다면 q에 넣어줌
}
}
}
return timeA[goal];
}
int main(){
int N;
int R;
vector<int>n;
//int n[100]={0} ;
vector<vector<int>> r;
//int r[100][100]={0};
int goal;
cin>>N>>R;
int nn,rr;
for(int i=0;i<N;i++) {
cin>>nn;
n.push_back(nn);
}
vector<int>line;
for(int k=0;k<R;k++) {
for(int j=0;j<2;j++) {
cin>>rr;
line.push_back(rr);
}
r.push_back(line);
line.clear();
}
cin>>goal;
cout<<solution(n,r,goal,N,R);
}
728x90