Lowest Common Ancestor - changicho/algorithm-training GitHub Wiki

์ตœ์†Œ ๊ณตํ†ต ์กฐ์ƒ (Lowest Common Ancestor)

๊ด€๋ จ ๋ฌธ์ œ

๋ฐฑ์ค€.1761.์ •์ ๋“ค์˜ ๊ฑฐ๋ฆฌ

๋ฐฑ์ค€.11438.LCA 2

ํ•„์š”ํ•œ ์ž๋ฃŒ๊ตฌ์กฐ

struct Node {
  int to, weight;
};

์›๋ฆฌ

LCA๋ฅผ ์ด์šฉํ•˜๋ฉด ๊ฐ ํŠธ๋ฆฌ๋“ค์˜ ์ตœ์†Œ ๊ณตํ†ต ์กฐ์ƒ์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋…ธ๋“œ A์™€ B์˜ ๋†’์ด๋ฅผ ๋งž์ถฐ์ค€ ๋’ค, ํ•œ๋‹จ๊ณ„์”ฉ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ์กฐ์ƒ์„ ์ฐพ๋Š” ๋ฐฉ์‹์ด๋‹ค.

์ด์ „์— ์žฌ๊ท€ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๊ฐ ๋…ธ๋“œ๋“ค์˜ ๋ถ€๋ชจ๋ฅผ ๊ฐฑ์‹ ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋ฅผ ์œ„ํ•ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฐ์—ด๋“ค์ด ํ•„์š”ํ•˜๋‹ค.

// node : ๋…ธ๋“œ์˜ ์ตœ๋Œ€ ๊ฐœ์ˆ˜ (MAX)
// level : log_w(MAX) + 1 (MAX_LEVEL)

bool visited[node];  // ๋…ธ๋“œ ๋ฐฉ๋ฌธ ์—ฌ๋ถ€
int parents[node][level]; // ๋ฐฐ์—ด(node: ์ •์ ๋ฒˆํ˜ธ level: 2^level๋ฒˆ์งธ ์กฐ์ƒ์„ ์˜๋ฏธ)
int depths[node]; // node์˜ ๋†’์ด๊ฐ€ ๋ช‡์ธ์ง€
int distArray[node];   // ๋ฃจํŠธ๋ถ€ํ„ฐ ๊ฐ ๋…ธ๋“œ๋“ค ๊นŒ์ง€์˜ ๊ฑฐ๋ฆฌ

์žฌ๊ท€ํ•จ์ˆ˜์™€ ๋ฐ˜๋ณต๋ฌธ์„ ์ด์šฉํ•ด ์ดˆ๊ธฐ๊ฐ’์„ ์„ค์ •ํ•œ๋‹ค.

// distance ๋ถ€๋ถ„์€ ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ ๊ณ ๋ ค
void recursive(int current, int depth, int distance) {
  visited[current] = true;
  depths[current] = depth;
  distArray[current] = distance;

  for (int next : graph[current]) {
    if (visited[next]) continue;

    parents[next][0] = current;
    recursive(next, depth + 1, distance + weights[current]);
  }
}
recursive(rootNode, 0); // ๋ฃจํŠธ๋…ธ๋“œ, 0
for (int level = 1; level <= MAX_LEVEL; level++) {
  for (int node = 1; node <= N; node++) {
    int parent = parents[node][level - 1];
    parents[node][level] = parents[parent][level - 1];
  }
}

์ตœ์†Œ ๊ณตํ†ต ์กฐ์ƒ์„ ์ฐพ๋Š” ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

int lowestCommonAncestor(int first, int second) {
  // ์ฒซ๋ฒˆ์งธ๊ฐ€ ์ž์‹ ๋…ธ๋“œ ๋†’์ด๋ฅผ ๋” ๋‚ฎ๋„๋ก ์„ค์ •
  if (depths[first] > depths[second]) {
    swap(first, second);
  }

  // ๋†’์ด๋ฅผ ๋งž์ถฐ์คŒ
  for (int level = MAX_LEVEL; level >= 0; level--) {
    if (depths[second] - depths[first] >= (1 << level)) {
      second = parents[second][level];
    }
  }

  if (first == second) {
    return first;
  }
  for (int level = MAX_LEVEL; level >= 0; level--) {
    if (parents[first][level] != parents[second][level]) {
      first = parents[first][level];
      second = parents[second][level];
    }
  }

  return parents[first][0];
}