847. Shortest Path Visiting All Nodes

  • ์ตœ์†Œ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ๋กœ BFS + memoization์„ ํ™œ์šฉํ•œ๋‹ค.
  • ์ผ๋ฐ˜์ ์ธ BFS์™€๋Š” ๋‹ค๋ฅธ ๋ฐฉ์‹์˜ memoization์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.
    • ์ผ๋ฐ˜์ ์ธ BFS์—์„œ๋Š” ๋ฐฉ๋ฌธํ•œ ๋…ธ๋“œ์˜ cost๋ฅผ memoizeํ•  ๋•Œ key๋กœ ๋…ธ๋“œ์˜ ID node ID๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ๋Š” node ID ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ•ด๋‹น ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ•˜๊ธฐ๊นŒ์ง€ ๋ฐฉ๋ฌธํ–ˆ๋˜ ๋ชจ๋“  ๋…ธ๋“œ์˜ ๋ชฉ๋กvisited node list(or state) ์„ key๋กœ ํ•ด์•ผ ํ•œ๋‹ค.
    • ๋ฌธ์ œ๋Š” visited node list๋ฅผ key๋กœ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ๋ฐ ์ „์ฒด ๋…ธ๋“œ์˜ ์ˆ˜๊ฐ€ 12๊ฐœ ์ดํ•˜์ด๋ฏ€๋กœ integer mask๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‘œํ˜„ํ•˜๊ธฐ๋กœ ํ•œ๋‹ค.
    • ๊ฒฐ๊ตญ cost map์˜ key๋Š” (node ID, mask)๊ฐ€ ๋œ๋‹ค.
  • ๋˜ํ•œ ๊ธฐ์กด๊ณผ๋Š” ๋‹ฌ๋ฆฌ ์‹œ์ž‘ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์‹œ์ž‘์ ์œผ๋กœ ํ•˜์—ฌ BFS๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค.
    • ์ด ๋ฌธ์ œ์˜ ๊ฒฝ์šฐ leaf node๊ฐ€ ์•„๋‹Œ ๋…ธ๋“œ์—์„œ ์‹œ์ž‘ํ•  ๊ฒฝ์šฐ ์ตœ์†Œ ๊ฒฝ๋กœ ๊ธธ์ด๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ leaf node๋“ค์˜ ๋ชฉ๋ก๋งŒ ๋ฝ‘์•„์„œ ์‹œ์ž‘์ ์œผ๋กœ ํ•˜์—ฌ BFS๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด ๋œ๋‹ค.
    • ๋งŒ์ผ leaf node๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด graph๊ฐ€ cycle์ด๋ผ๋Š” ์˜๋ฏธ์ด๋ฏ€๋กœ ์ž„์˜์˜ ๋…ธ๋“œ๋ฅผ ํ•˜๋‚˜๋งŒ ๊ณจ๋ผ์„œ ์‹œ์ž‘ํ•ด๋„ ๋ฌด๋ฐฉํ•˜๋‹ค.
  • priority_queue๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์žฅ cost๊ฐ€ ๋‚ฎ์€ (node ID, mask)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํƒ์ƒ‰์„ ์ง„ํ–‰ํ•œ๋‹ค.
    • ์ธ์ ‘ ๋…ธ๋“œ next in graph[curr]๋งˆ๋‹ค
      • ๋‹ค์Œ ๋…ธ๋“œnext๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ key๋ฅผ ์ •ํ•œ๋‹ค next key = (next, currMask | 1 << next)
      • cost[next key]๊ฐ€ cost[curr key] + 1๋ณด๋‹ค ํฐ ๊ฒฝ์šฐ cost[next key]๊ฐ’์„ cost[curr key] + 1๋กœ ๊ฐฑ์‹ ํ•˜๊ณ  priority_queue์— next key๋ฅผ ๋„ฃ๋Š”๋‹ค.
  • ํƒ์ƒ‰์ด ์ข…๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด ๊ฐ ๋…ธ๋“œ์— ๋Œ€ํ•ด์„œ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ•œ ์ƒํƒœkey = (ID, allMask)์˜ cost ์ค‘ ๊ฐ€์žฅ ์ž‘์€ ๊ฐ’์„ ๊ฒฐ๊ณผ๋กœ ๋Œ๋ ค์ค€๋‹ค.
class Solution { public: vector<int> getLeafNodes(vector<vector<int>>& graph) { vector<int> result; for (int i = 0; i < graph.size(); ++i) { if (graph[i].size() == 1) result.push_back(i); } return result; } int shortestPathLength(vector<vector<int>>& graph, int start, int allMask) { // (node ID, mask) using IDMask = pair<int, int>; map<IDMask, int> cost; // compare two key with cost auto compare = [&cost](IDMask& a, IDMask& b) { return cost[a] < cost[b]; }; // priority queue of IDMask using PQ = priority_queue<IDMask, vector<IDMask>, decltype(compare)>; PQ pq(compare); // start condition int startMask = 1 << start; cost[{start, startMask}] = 0; pq.emplace(start, startMask); int curr, currMask; while (!pq.empty()) { tie(curr, currMask) = pq.top(); pq.pop(); int currCost = cost[{curr, currMask}]; // for each next node for (auto next : graph[curr]) { // mark visited to mask auto nextMask = currMask | 1 << next; // check next cost auto& nextCost = cost[{next, nextMask}]; if (nextCost == 0 || currCost + 1 < nextCost) { nextCost = currCost + 1; // add next key if mask isn't all mask if (nextMask != allMask) pq.emplace(next, nextMask); } } } int result = -1; for (int i = 0; i < graph.size(); ++i) { // find minimum cost with all mask (all visited) auto itr = cost.find({i, allMask}); if (itr == cost.end()) continue; auto currCost = itr->second; if (result == -1 || currCost < result) result = currCost; } return result; } int shortestPathLength(vector<vector<int>>& graph) { // get leaf nodes auto leafNodes = getLeafNodes(graph); // graph is cycle if (leafNodes.empty()) { leafNodes.push_back(0); } // get all mask int allMask = 0; for (int i = 0; i < graph.size(); ++i) { allMask |= 1 << i; } int result = -1; for (auto start : leafNodes) { // for each leaf node int length = shortestPathLength(graph, start, allMask); if (result == -1 || length < result) result = length; } return result; } };