본문 바로가기

ProgramSoliving

백준 : 3665 (위상정렬)

반응형

https://www.acmicpc.net/problem/3665

 

3665번: 최종 순위

문제 올해 ACM-ICPC 대전 인터넷 예선에는 총 n개의 팀이 참가했다. 팀은 1번부터 n번까지 번호가 매겨져 있다. 놀랍게도 올해 참가하는 팀은 작년에 참가했던 팀과 동일하다. 올해는 인터넷 예선 ��

www.acmicpc.net

 

깔끔한 풀이가 안떠올라서 생각나는 데로 풀었다.

 

만약 어떤 팀의 우승 순서가 이어진다면 노드로 이어보면

5 <- 4<- 3<- 2<- 1 형태의 그래프를 이을 수 있다.

 

이것을 위상그래프로 생각해본다면

5<-4, 5<-3, 5<-2, 5<-1

4<-3, 4<-2, 4<-1

3<-2, 3<-1

2<-1 

 

그래프가 그려지는 것을 알 수 있고 바꾸는 두 정점에대하여 바꾼뒤 들어오는 차수와 나가는 차수를 이용해서 위상정렬을 할 수 있다.

 

문제에서는 여러 케이스가 아닌 오직 하나의 위상정렬만 되는 case에 대해서만 정답을 출력하니

Parrent 차수 + childe차수 == N-1 을 유지하는 위상정렬 중에 rank가 옳바르게 뽑힌 녀석들만 출력하면 된다.

 

이렇게하면 정답은 나오지만 깔끔한 풀이가 아닌것 같아서 다른 블로그를 보고 참조해보겠다.

내가 푼 풀이

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;

public class B3665 {
	static int Tc;
	static int N, M;
	static int seq[];
	static ArrayList<Integer> Vex[];
	static int parrent[];
	static int child[];
	static int rank[];

	public static void main(String[] args) throws NumberFormatException, IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		StringBuilder sb = new StringBuilder();
		Tc = Integer.parseInt(br.readLine());

		while (Tc-- != 0) {
			N = Integer.parseInt(br.readLine());
			seq = new int[N];
			st = new StringTokenizer(br.readLine());
			for (int n = 0; n < N; n++)
				seq[n] = Integer.parseInt(st.nextToken());

			Vex = new ArrayList[N + 1];
			for (int n = 1; n <= N; n++)
				Vex[n] = new ArrayList<>();

			for (int i = 0; i < N - 1; i++) {
				for (int j = i + 1; j < N; j++) {
					Vex[seq[j]].add(seq[i]);
				}
			}

			M = Integer.parseInt(br.readLine());
			for (int m = 0; m < M; m++) {
				st = new StringTokenizer(br.readLine());
				// a <- b
				int a = Integer.parseInt(st.nextToken());
				int b = Integer.parseInt(st.nextToken());

				// b <- a 엿던것을 a < - b로 바꾼다.

				// b <- a edge 제거
				boolean isChange = false;
				for (Iterator<Integer> it = Vex[a].iterator(); it.hasNext();) {
					int cur = it.next();
					if (cur == b) {
						it.remove();
						isChange = true;
						break;
					}
				}

				if (isChange) {
					// a<-b 엣지 추가
					Vex[b].add(a);
				} else {
					for (Iterator<Integer> it = Vex[b].iterator(); it.hasNext();) {
						int cur = it.next();
						if (cur == a) {
							it.remove();
							break;
						}
					}
					Vex[a].add(b);
				}
			}

			// 연결이 끝나면 위상을 확인하는데 parrent child 수라 확인한다.
			parrent = new int[N + 1];
			child = new int[N + 1];
			rank = new int[N + 1];

			// parrent + child 의 합은 항상 N-1 이어야한다.

			for (int n = 1; n <= N; n++) {
				for (int next : Vex[n]) {
					// next <- n 노드이다.
					parrent[n]++;
					child[next]++;
				}
			}

			boolean isPossible = false;

			// rank를 구한다.
			for (int n = 1; n <= N; n++) {
				if ((parrent[n] + child[n]) != N - 1) {
					isPossible = true;
					break;
				}
				rank[parrent[n] + 1] = n;
			}

			for (int n = 1; n <= N; n++) {
				if (rank[n] == 0) {
					isPossible = true;
					break;
				}
			}

			if (isPossible) {
				sb.append("IMPOSSIBLE\n");
			} else {
				for (int n = 1; n <= N; n++) {
					sb.append(rank[n]).append(' ');
				}
				sb.append('\n');
			}

		}
		System.out.println(sb.toString());
	}
}

 

다른사람 방법

입력과 위상이 바뀌는 정보 까지는 똑같다.

1. inDegree가 0인 애들을 기준으로 q에다가 저장한다.

2. q에서 뺏을 때 q 사이즈가 0이 아닌경우에는 현재 inDegree가 0인 애들이 동시에 존재한다는거니 impossible을 반환한다.

3. q 사이즈가 0이 아닌경우에는 pop된 node를 기준으로 연결된 그래프들의 inDegree를 --한다.
이때 inDegree가 0이 되는 애들을 q에 push한다.

위의 과정을 반복할때 inDegree가 0이 되는 순서가 순서의 역순이 된다.
반응형

'ProgramSoliving' 카테고리의 다른 글

프로그래머스 : 타겟 넘버  (0) 2020.09.11
프로그래머스 : 방금그곡  (0) 2020.07.25
백준 : 5670  (0) 2020.07.18
백준 : 14725 (트라이)  (0) 2020.07.18
백준 : 10266  (0) 2020.07.18