Обнаружение цикла в Графике с использованием find и Union

    int main()
{

char line[100];
int N = 5;
vector<int>adj[N];
FILE *in = fopen("test.txt", "r");

for (int i = 1; i <= N; i++) // Accepting the graph from file
{
fgets(line, 100, in);

char *pch = strtok(line, "\t \n");
int u = atoi(pch);

pch = strtok(NULL, "\t \n");
while (pch != NULL)
{
int v = atoi(pch);
adj[u-1].push_back(v);
pch = strtok(NULL, "\t \n");
}

}
for( int i = 0; i < 5; i++ )  // printing the graph
{
for( int p = 0 ; p < adj[i].size(); p++ )
{
cout<< i+1 << " , "<< adj[i][p]<<endl;
}
}

if (isCycle(adj))
cout << endl << "graph contains cycle" ;
else
cout << endl << "graph  does not contain cycle" ;

return 0;
}

int isCycle( vector<int> adj[] )
{
// Allocate memory for creating V subsets
int *parent = (int*) malloc( 5 * sizeof(int) );

// Initialize all subsets as single element sets
memset(parent, -1, sizeof(int) * 5);
for(int i = 0; i < 5; i++)
{
for( int p = 0 ; p < adj[i].size(); p++ )
{
int x = find(parent,i);
int y = find(parent, adj[i][p]-1);  // I think problem is here

if (x == y)
return 1;

Union(parent, x, y);
}
}
return 0;
}

// A utility function to find the subset of an element i
int find(int parent[], int i)
{
if (parent[i] == -1)
return i;
return find(parent, parent[i]);
}

// A utility function to do union of two subsets
void Union(int parent[], int x, int y)
{
int xset = find(parent, x);
int yset = find(parent, y);
parent[xset] = yset;
}

Файл test.txt содержит следующие входные данные:

1 2 3
2 1 4 5
3 1
4 2
5 2

Первый столбец содержит вершины (1 — 5)

1 2 3

Выше ряд (первый ряд) означает, Node 1 связан с Node 2 а также Node 3

2 1 4 5

Выше ряда (2-й ряд) означает, Node 2 связан с Node 1 , Node 4 а также Node 5

Теперь здесь проблема в том, чтобы взять любой вклад, который он всегда говорит: Графики содержат цикл. (Хотя граф не содержит цикл)
Теперь в приведенном выше входном графе не содержится цикл, но говорят, что граф содержит цикл.
Где я не прав ?? Может кто-нибудь мне помочь ??

1

Решение

Проблема с вашим вход, но сначала немного предыстории:


Предыстория использования Union-Find для обнаружения циклов

Алгоритм Union-Find ожидает неориентированный граф.

По сути, это работает следующим образом:

  • Создайте набор ребер, которые в основном являются парами идентификаторов узлов
    • например (1,2), (2,3)
  • Для каждого края:
    • найти «родителя» левой стороны (найти Порция)
    • найти «родителя» правой стороны (найти Порция)
    • если родители идентичны, у вас есть цикл
    • в противном случае родитель левой стороны теперь равен родителю правой стороны (союз Порция)

«Родитель»: произвольное обозначение между двумя ненаправленными узлами. Произвольно мы говорим, что один является родителем другого, а не наоборот.

  • Во-первых, ни у одного узла нет родителя (значение которого в -1 используется для.
  • Затем, перебирая ребра, вы назначаете этих родителей
    • если родитель не существует, узел является его собственным родителем (0 — родитель 0, 1 — родитель 1 и т. д.)
    • после вычисления родителей для обеих сторон ребра (например, 1 а также 2 для края (1, 2) Сначала мы увидим, что их родители не одинаковы (родитель 1 — 1, а родитель 2 — 2).
    • На данный момент мы союз родители, чтобы сделать их одинаковыми
      • родитель 1 становится 2, а родитель 2 остается 2
      • часть «Объединение» следует рассматривать как «объединение двух подмножеств узлов под общим родителем», поэтому подмножества 1 и 2 становятся (1, 2), чьим родителем является 2.

Однако, как ваш алгоритм написан, это предполагает что если мы впервые получим преимущество (1, 2)тогда мы будем не позже получить преимущество (2, 1), Ваш вклад не согласен. Поэтому у вас есть циклы.

Если вы удалите эти избыточные ребра и предоставите ввод, как:

1 2 3
2 4 5
3
4
5

Это будет работать(У меня C ++ — кстати, черт побери из твоего кода). Однако в противном случае он будет правильно сообщать о цикле

Ваш вызов

Поэтому стоит принять во внимание, что ваш ввод отличается от того, что ожидает ваш алгоритм. То есть, вы, вероятно, не должны создавать ребра, если они уже существуют.

Что я бы порекомендовал:
— поскольку график не ориентирован, сохраняйте ребра с меньшим идентификатором всегда слева. Вы можете сохранить отсортированный список ребер и не вставлять повторяющиеся ребра (используйте std::set), чтобы представить свой крайний список).

Полученный код выглядит примерно так (используя cin для ввода):

using edge_t = std::pair<int, int>;
using edge_list_t = std::set<edge_t>;
using parent_child_map_t = std::map<int, int>;

// find the parent for an id
int find(const parent_child_map_t& idToParent, int id)
{
auto iter = idToParent.find(id);
if (iter == idToParent.end())
return id;
return find(idToParent, iter->second);
}

// lhsId and rhsId are two sides to an edge
// this Union function will determine who is the "parent"// arbitrarily choosing the rhsId's parent as lhsId's parent
void ComputeUnion(parent_child_map_t* idToParent, int lhsId, int rhsId)
{
if (!idToParent)
return;

int xsubset = find(*idToParent, lhsId);
int ysubset = find(*idToParent, rhsId);
(*idToParent)[xsubset] = ysubset;
}

bool HasCycle(const edge_list_t& edges )
{
// determine parents
parent_child_map_t idToParent;

for (auto&& nextEdge : edges)
{
int x = find(idToParent, nextEdge.first);
int y = find(idToParent, nextEdge.second);
if (x == y)
return true;
ComputeUnion(&idToParent, x, y);
}

return false;
}

int main()
{
edge_list_t edges;

std::string nextline;
while(std::getline(std::cin, nextline))
{
std::istringstream nextLineStream(nextline);
int id;
nextLineStream >> id;
int nextNeighbor;
while(nextLineStream >> nextNeighbor)
{
int lhs = std::min(id, nextNeighbor);
int rhs = std::max(id, nextNeighbor);
edges.insert(std::make_pair(lhs, rhs));
}
}

if (HasCycle(edges))
std::cout << "Graph contains cycle\n";
else
std::cout << "Graph does not contain cycle\n";

return 0;
}

И теперь он больше не сообщает о цикле в вашем входе!

Но, если мы предоставим входные данные следующим образом (обратите внимание на дополнительный край (4,1)):

1 2 3
1 2 3
2 1 4 5
3 1
4 2 1
5 2

Тогда он правильно сообщает цикл!

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]