- ์ต์ ๊ฒฝ๋ก๋ฅผ ๊ตฌํ๋ ๋ฌธ์ ๋ก 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;
}
};