Ответ, расположенный веше в целом работает, но в нем очень быстро возрастает сложность. Есть взять 11 вершин и каждую соединить с каждой, то в какой-то момент в оперативной памяти будут десятки миллионов строк. Вот мой запрос. Описанный граф он "проглатывает" за примерно 1.5 секунд (реализации алгоритма выше я не дождался и за 10 минут для такого графа).
WITH
vals AS (SELECT t_a.a
, t_b.b
FROM (SELECT level AS a FROM dual CONNECT BY level <= 11) t_a
CROSS JOIN (SELECT level AS b FROM dual CONNECT BY level <= 11) t_b)
, snowflakes
AS (SELECT ',' || listagg(decode(vertices.a, edges.b, edges.a, edges.a, edges.b), ',')
WITHIN GROUP ( ORDER BY decode(vertices.a, edges.b, edges.a, edges.a, edges.b)) ||
',' AS gr
, vertices.a AS core
FROM (SELECT DISTINCT least(a, b) AS a, greatest(a, b) AS b FROM vals) edges
JOIN (SELECT a FROM vals UNION SELECT b FROM vals) vertices ON vertices.a = edges.a OR vertices.a = edges.b
GROUP BY vertices.a)
, burning_graph (gr, core_str, lvl)
AS (SELECT s.gr
, to_char(s.core) AS core_str
, 1 AS lvl
FROM snowflakes s
WHERE core = 3 -- !! Вот тут выбираем с какой вершины начать поиск
UNION ALL
SELECT ',' ||
(SELECT listagg(value, ',') WITHIN GROUP (ORDER BY to_number(value)) AS sorted_result
FROM (SELECT regexp_substr(combined_str, '[^,]+', 1, level) AS value
FROM (SELECT listagg(value, ',') WITHIN GROUP (ORDER BY to_number(value)) AS combined_str
FROM (SELECT regexp_substr(r.gr || s.gr, '[^,]+', 1, level) AS value
FROM dual
CONNECT BY level <= length(r.gr || s.gr) - length(replace(r.gr || s.gr, ',')) + 1)
WHERE value IS NOT NULL)
CONNECT BY level <= length(combined_str) - length(replace(combined_str, ',')) + 1
MINUS
SELECT regexp_substr(r.core_str || ',' || to_char(s.core), '[^,]+', 1,level) AS value
FROM dual
CONNECT BY level <= length(r.core_str || ',' || to_char(s.core)) -
length(replace(r.core_str || ',' || to_char(s.core), ',')) +
1)
WHERE value IS NOT NULL) || ',' AS gr
, r.core_str || ',' || to_char(s.core) AS core_str
, r.lvl + 1 AS lvl
FROM burning_graph r
JOIN snowflakes s ON r.gr LIKE ',' || s.core || ',%')
, subgraph_result AS (SELECT to_number(regexp_substr(b.core_str, '[^,]+', 1, level)) AS vertex_num
FROM (select core_str from burning_graph WHERE lvl = (SELECT max(lvl) FROM burning_graph)) b
CONNECT BY level <= length(b.core_str) - length(replace(b.core_str, ',')) + 1)
SELECT * FROM subgraph_result ORDER BY vertex_num;
Безусловно, можно попробовать и с более заковыристым графом, чтобы убедиться, что алгоритм не вытаскивает просто все вершины:
WITH
vals AS (SELECT 1 AS a, 2 AS b FROM dual UNION ALL
SELECT 2 AS a, 5 AS b FROM dual UNION ALL
SELECT 3 AS a, 5 AS b FROM dual UNION ALL
SELECT 6 AS a, 5 AS b FROM dual UNION ALL
SELECT 3 AS a, 4 AS b FROM dual UNION ALL
SELECT 7 AS a, 8 AS b FROM dual)
Вот так он выглядит (в последней раз я начинал с вершины 2, поэтому она подкрашена):
