백준 문제풀이(JAVA)/트리

백준 1761번(JAVA) - 정점들의 거리

붉은범 2023. 11. 4. 17:47
반응형
import java.util.*;
import java.io.*;

class Node
{
	int v;
	int w;
	Node(int v, int w)
	{
		this.v=v;
		this.w=w;
	}
}

public class Main {

	public static ArrayList<Node>[] arr;
	public static int N;
	public static int[] Depth; // 깊이
	public static int[][] parent;// parent[0][3] 은 3번 노드의 2의0승 부모, 
	//parent[5][3]은 3번 노드의 2의 5승부모, 즉 32번째 부모
	public static int[][] length;// length[5][3] 은 3번 노드부터 2의0승 부모까지의 길이
	public static int LogN = 17;// 2의 몇제곱까지 계산할지를 결정
	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		N=Integer.parseInt(br.readLine());
		String[] s;
		arr = new ArrayList[N+1];
		parent = new int[LogN+1][N+1];
		Depth = new int[N+1];
		length = new int[LogN+1][N+1];
		for(int i=1;i<=N;i++)
		{
			arr[i] = new ArrayList<Node>();
		}
		for(int i=0;i<N-1;i++)
		{
			s=br.readLine().split(" ");
			int u=Integer.parseInt(s[0]);
			int v=Integer.parseInt(s[1]);
			int w=Integer.parseInt(s[2]);
			arr[u].add(new Node(v,w));
			arr[v].add(new Node(u,w));
		}
		BFS();//트리 생성
		for(int i=1;i<=LogN;i++)//2의n승 부모와 , 그 부모까지의 거리
		{
			for(int j=1;j<=N;j++)
			{
				parent[i][j]=parent[i-1][parent[i-1][j]];
				length[i][j]=length[i-1][j]+length[i-1][parent[i-1][j]];
			}
		}
		int M=Integer.parseInt(br.readLine());
		for(int i=0;i<M;i++)
		{
			s=br.readLine().split(" ");
			int u = Integer.parseInt(s[0]);
			int v = Integer.parseInt(s[1]);
			if(Depth[u]<Depth[v])//오른쪽인자가 더 깊이가 깊게
			{
				System.out.println(dist(u,v));
			}
			else
			{
				System.out.println(dist(v,u));
			}
		}

	}
	public static void BFS()//트리 만들기, 루트 노드는 1번으로
	{
		Queue<Integer> q=new LinkedList<Integer>();
		boolean[] visited = new boolean[N+1];
		q.add(1);
		Depth[1]=0;
		while(!q.isEmpty())
		{
			int temp = q.poll();//현재 노드번호
			if(visited[temp])
			{
				continue;
			}
			visited[temp]=true;
			for(Node next : arr[temp])
			{
				if(visited[next.v])//부모로 역행 막아준다
				{
					continue;
				}
				Depth[next.v]=Depth[temp]+1;;
				parent[0][next.v]=temp;
				length[0][next.v]=next.w;
				q.add(next.v);
			}
		}
	}
	public static int log(int value)
	{
		int k=0;
		while((1<<k<=value))
		{
			k++;
		}
		return k-1;
	}
	
	public static int dist(int u,int v)//u와 v의 경로의 비용
	{
		int result = 0;
		while(Depth[u]!=Depth[v])
		{
			int temp= Depth[v]-Depth[u];
			result = result + length[log(temp)][v];
			v=parent[log(temp)][v];
		}
		if(u==v)//깊이를 맞춰줬는데 같은 노드일수도있다. 즉 한 노드가 다른노드의 후손이었을수도
		{
			return result;
		}
		for(int i = LogN; i>=0; i--)
		{
			if(parent[i][u]!=parent[i][v])//공통조상 한 칸 밑에까지 올라가준다
			{
				result = result + length[i][u];
				u = parent[i][u];
				result = result + length[i][v];
				v = parent[i][v];//올라가면서 거리들은 계속 더해준다
			}
		}
		return result + length[0][u] +length[0][v];//현재 U와V는 공통조상 한 칸 밑에까지 왔으므로
	}
}

 

 

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

 

1761번: 정점들의 거리

첫째 줄에 노드의 개수 N이 입력되고 다음 N-1개의 줄에 트리 상에 연결된 두 점과 거리를 입력받는다. 그 다음 줄에 M이 주어지고, 다음 M개의 줄에 거리를 알고 싶은 노드 쌍이 한 줄에 한 쌍씩

www.acmicpc.net

 

반응형