import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import java.util.StringTokenizer;
class Edge {
int start, end;
int weight;
public Edge(int start, int end, int weight) {
this.start = start;
this.end = end;
this.weight = weight;
}
}
class Node<T> extends ArrayList<T> {
public static Node[] Tree;
public int nodeNo;
public int parentNo;
public int rank;
public void makeSet(int x) {
nodeNo = x;
parentNo = x;
rank = 0;
}
public int findSet() {
Stack<Integer> nodeStack = new Stack<>();
nodeStack.add(nodeNo); // 검색 노드 조건
Node moveNode = Tree[nodeNo];
while (moveNode.nodeNo != moveNode.parentNo) { // 부모 노드 조건
moveNode = Tree[moveNode.parentNo];
nodeStack.add(parentNo);
}
if (nodeStack.size() > 1) { // 찾은 부모가 있다면
int represent = moveNode.nodeNo;
while (!nodeStack.isEmpty()) { // 부모노드를 가르키도록
Tree[nodeStack.pop()].parentNo = represent;
}
}
return moveNode.nodeNo;
}
public void unionSet(Node<T> node) {
Node first = Tree[this.nodeNo];
Node second = Tree[node.nodeNo];
int f = first.findSet();
int s = second.findSet();
if (f == s) {
return;
}
first = Tree[f];
second = Tree[s];
if (first.rank > second.rank) {
second.parentNo = first.nodeNo;
} else {
first.parentNo = second.nodeNo;
if (this.rank == node.rank) {
node.rank++;
}
}
}
}
class Solution {
static int DATA_SIZE;
static Node<Edge>[] tree;
static Boolean isFound;
static int[] visited;
static int[] distance;
static boolean Debug = true;
public static void main(String args[]) throws Exception {
BufferedReader br;
if (Debug) {
File f = new File("C:\\Users\\wvimi\\Downloads", "input (29).txt");
FileReader reader = new FileReader(f);
br = new BufferedReader(reader);
} else {
br = new BufferedReader(new InputStreamReader(System.in));
}
StringTokenizer st;
int start, end, weight;
int testNo = Integer.parseInt(br.readLine());
for (int T = 1; T <= 6; T++) {
st = new StringTokenizer(br.readLine());
int nodeNum = Integer.parseInt(st.nextToken());
int taskNum = Integer.parseInt(st.nextToken());
StringBuffer sb = new StringBuffer();
System.out.print(String.format("#%d", T, nodeNum, taskNum));
log("");
tree = new Node[nodeNum + 1];
visited = new int[nodeNum + 1];
distance = new int[nodeNum + 1];
Node.Tree = tree;
for (int i = 0; i < tree.length; i++) {
tree[i] = new Node<Edge>();
tree[i].makeSet(i);
}
// [방법2]
ArrayList<Integer> representList = new ArrayList<>();
for (int i = 0; i < taskNum; i++) {
st = new StringTokenizer(br.readLine());
switch (st.nextToken()) {
case "!":
start = Integer.parseInt(st.nextToken());
end = Integer.parseInt(st.nextToken());
weight = Integer.parseInt(st.nextToken());
tree[start].add(new Edge(start, end, weight));
tree[end].add(new Edge(end, start, -1 * weight));
tree[start].unionSet(tree[end]);
break;
case "?":
start = Integer.parseInt(st.nextToken());
end = Integer.parseInt(st.nextToken());
// findPath(start, end);
int a = tree[start].findSet();
int b = tree[end].findSet();
if (a == b) {
// [방법2 ] 무게의 상대값을 기록하여 재활용하기
// if(!representList.contains((Integer) a)) {
// representList.add(a);
// visited = new int[nodeNum + 1];
// distance = new int[nodeNum + 1];
// }
int w_end = findWeight(end);
int w_start = findWeight(start);
int answer = w_end - w_start;
sb.append(String.format(" %d", answer));
} else {
sb.append(" UNKOWN");
}
break;
}
}
System.out.println(sb.toString());
}
}
private static int findWeight(int nodeNo) {
if (visited[nodeNo] == 1) {
log(String.format("3. distance[%d] = %d", nodeNo, distance[nodeNo]));
return distance[nodeNo];
}
// 연결된 노드를 찾는다.
int subParent = 0;
Queue<Integer> que = new LinkedList();
que.add(nodeNo);
Stack<Integer> visiting = new Stack();
while (!que.isEmpty()) {
int reStart = que.poll();
log(String.format("nodeNo:%d reStart: %d", nodeNo, reStart));
for (Edge line : tree[reStart]) {
log(String.format("visited[%d] = %d", line.end, visited[line.end]));
if (visited[line.end] == 1 || line.end == tree[nodeNo].parentNo) {
// 무게가 기록된 연결된 노드를 찾음 || 부모노드
subParent = line.end;
break;
}
que.add(line.end);
visited[line.end] = 1;
visiting.add(line.end);
}
}
for (int i : visiting) {
visited[i] = 0;
}
que = new LinkedList();
que.add(subParent);
log("subParent 진입: " + subParent);
while (!que.isEmpty()) {
int reStart = que.poll();
for (Edge line : tree[reStart]) {
if (visited[line.end] == 1) {
continue;
}
// que.add(line.end);
que.add(line.end);
visited[line.end] = 1;
distance[line.end] = distance[line.start] + line.weight;
log(String.format("2. distance[%d] = %d", line.end, distance[line.end]));
if (line.end == nodeNo) {
return distance[line.end];
}
}
}
return -1;
}
private static void log(String input) {
if (true) {
System.out.println(input);
}
}
}
'Knowledge > 알고리즘' 카테고리의 다른 글
[와우패스] 동서남북 복불복 (0) | 2017.10.05 |
---|---|
2112. [모의 SW 역량테스트] 보호 필름 (0) | 2017.10.05 |
1167.백준 트리의 지름 (시간초과...) (0) | 2017.10.01 |
11725.백준 트리의 부모 찾기 (0) | 2017.10.01 |
1230. [S/W 문제해결 기본] 8일차 - 암호문3 (0) | 2017.09.30 |