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
Теперь здесь проблема в том, чтобы взять любой вклад, который он всегда говорит: Графики содержат цикл. (Хотя граф не содержит цикл)
Теперь в приведенном выше входном графе не содержится цикл, но говорят, что граф содержит цикл.
Где я не прав ?? Может кто-нибудь мне помочь ??
Проблема с вашим вход, но сначала немного предыстории:
Алгоритм Union-Find ожидает неориентированный граф.
По сути, это работает следующим образом:
(1,2), (2,3)
«Родитель»: произвольное обозначение между двумя ненаправленными узлами. Произвольно мы говорим, что один является родителем другого, а не наоборот.
-1
используется для.1
а также 2
для края (1, 2)
Сначала мы увидим, что их родители не одинаковы (родитель 1 — 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
Других решений пока нет …