[DFS] 문제 : 고대어 사전
2017. 8. 7. 23:42ㆍ[개발] 지식/알고리즘 문제풀이
고대어 사전
소스
package apss;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Dictionary {
public static int[][] adj;
public static boolean[] seen = new boolean[26];
public static List<Integer> order;
public static void main(String[] args) throws NumberFormatException, IOException {
// TODO Auto-generated method stub
System.setIn(new FileInputStream("C://dev/sample_input.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine().trim());
for( int testCase = 1; testCase <= T; testCase++ ){
int N = Integer.parseInt(br.readLine().trim());
String[] words = new String[N];
for( int i = 0; i < N; i++ ){
words[i] = br.readLine().trim();
}
makeGraph(words);
List<Integer> rt = topologicalSort();
if(rt.isEmpty()){
bw.write("INVALID HYPOTHESIS");
}else{
for(int i=0; i<rt.size(); i++){
bw.write(Character.toString((char)((int)rt.get(i)+'a')));
}
}
bw.write("\n");
bw.flush();
}
bw.close();
}
// 주어진 단어들로부터 알파벳 간의 선후관계 그래프를 생성한다.
public static void makeGraph(String[] words){
adj = new int[26][26];
for(int j = 1; j < words.length; j++){
int i = j - 1;
int len = Math.min(words[i].length(), words[j].length());
for(int k = 0; k < len; k++){
if(words[i].charAt(k) != words[j].charAt(k)){
int a = words[i].charAt(k) - 'a';
int b = words[j].charAt(k) - 'a';
adj[a][b] = 1;
break;
}
}
}
}
public static void dfs(int here){
seen[here] = true;
for( int there = 0; there < adj.length; there++ ){
if(adj[here][there] == 1 && !seen[there]){
dfs(there);
}
}
order.add(here);
}
public static List<Integer> topologicalSort(){
int n = adj.length;
seen = new boolean[n];
order = new ArrayList<Integer>();
// dfsAll의 역할?
for(int i=0; i<n; i++){
if(!seen[i]){
dfs(i);
}
}
Collections.reverse(order.subList(0, order.size()));
for(int i=0; i<n; i++){
for(int j=i+1; j<n; j++){
if(adj[order.get(j)][order.get(i)] == 1){
return new ArrayList<Integer>();
}
}
}
return order;
}
}
풀이
1. 위상정렬을 위해 방향 그래프를 만든다.
2. 위상정렬을 dfs로 수행한다.
3. 사이클이 존재하는지 검사. 존재한다면 'INVALID HYPOTHESIS' 출력
4. 결과 출력
adj는 26개 알파벳들의 순서를 나타내는 인접행렬이다.
adj[0][1] == 1 이면 0번 알파멧(a)가 1번 알파벳(b)보다 사전순으로 앞에 온다는 것을 의미한다.
makeGraph 함수에서는 adj 행렬을 만들어 그래프를 생성한다.
dfs 메서드가 리턴하는 순으로 list에 넣으면 위상정렬의 '역'이 된다.
따라서 생성된 위상정렬을 뒤집기 위해 Collections.reverse() 메서드를 사용했음에 주목한다.
위상정렬의 결과는 사이클이 존재할 수 없다. 즉 DAG가 되면 안된다. 만약 사이클이 존재한다면 사전순으로 정렬할 수 없는 input이라고 볼 수 있다.
사이클 여부를 확인하기 위해 이중 for문으로 위상정렬 결과를 검사한다. 만약 사이클이 존재하면 empty list를 리턴해서 분기처리 한다.
#DFS #위상정렬
'[개발] 지식 > 알고리즘 문제풀이' 카테고리의 다른 글
벨만-포드 알고리즘 (0) | 2017.09.20 |
---|---|
[DFS] 오일러 서킷 (1) | 2017.08.20 |
[DFS] DFS (0) | 2017.08.07 |
(작성중)Dynamic Programming (0) | 2017.06.26 |
소수들의 곱셈 (0) | 2017.06.19 |
<