Я хотел бы создать набор, который имеет транзитивные пары. Мой вклад будет иметь вид pair<int, int>
и мне нужен набор, который имеет все транзитивные пары для заданных входов.
Например, если у меня есть пары {1, 2} {2, 1} {2, 3} {3,4} в качестве входов, то мне нужно иметь SET, который имеет пары {{1,2}, {2, 1}, {1, 3}, {3, 4}, {1, 4}, {2, 4}}. Мне также нужно выяснить, является ли данная пара членом этого транзитивного набора.
Есть ли какая-либо встроенная структура данных / библиотека STL, которая позволит мне сделать это в C ++?
У вас есть график, и вы хотите превратить его в свободную категорию, AKA — транзитивное замыкание этого графика.
Ваш int
парные элементы — это вершины, сами пары — ребра, это ваш граф. Теперь свободной категорией на графе является тот граф с законом композиции ребер и всеми дополнительными ребрами, которые могут быть созданы законом. Закон гласит, что
f
который бежит из a
в b
g
который бежит из b
в c
f∘g
который бежит из a
в c
(f∘g)∘h = f∘(g∘h)
)(Каждая категория также имеет единичные ребра, обозначенные 1
a
которые бегут от a
в a
для каждой вершины a
и закон, который говорит, что для каждой стрелки f
который бежит из a
в b
, 1
a
∘f = f∘1
b
= f
, но речь не о тех).
Общеобразовательная часть этого ответа настоящим завершена.
В стандартной библиотеке C ++ нет соответствующих алгоритмов, но вы можете проверить boost::graph
или любая другая граф-ориентированная библиотека. boost::graph
имеет transitive_closure
метод, который как раз то, что вы хотите.
Вы можете представить свой набор с помощью:
set<pair<int, int>> myset;
Транзитивное замыкание затем может быть вычислено с помощью:
void transitive_closure(set<pair<int, int>>& s)
{
set<pair<int, int>> a; // missing nodes to add
for (auto i = s.cbegin(); i != s.cend(); i++)
{
for (auto j = i; ++j != s.cend(); j)
{
if (i->second == j->first
&& i->first != j->second
&& s.count(make_pair(i->first, j->second))==0 )
a.insert(make_pair(i->first, j->second));
}
}
if (!a.empty()) {
for (auto p : a)
s.insert(p);
transitive_closure(s);
}
}
Это не самый оптимизированный алгоритм, потому что рекурсия повторит некоторые сравнения. Но это работает. Кстати, я думаю, что вы забыли {2, 3} в наборе результатов.
Чтобы проверить, принадлежит ли пара к набору, просто проверьте, s.count(make_pair(i->first, j->second)!=0