使用查找和联合检测图形中的周期
Detection of cycle in Graph using find and 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
上行(第二行)表示,Node 2
连接到Node 1
、Node 4
和Node 5
现在这里的问题是,取任何它总是说的输入:图包含循环。虽然图不包含循环)现在在上面的输入图中不包含周期,但说图形包含周期。 我错在哪里??谁能帮我??
问题出在您的输入上,但首先是一些背景:
使用联合查找发现周期的背景
联合查找算法需要一个无向图。
它基本上工作如下:
- 创建一组基本上是节点 ID 对的边
- 例如
(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++了你的代码)。但是,否则它将正确报告周期
您的挑战
因此,要考虑到您的输入与您的算法预期不同。也就是说,如果边已经存在,则可能不应创建边。
我建议: - 由于图形是无向的,因此将较小的 ID 始终存储在左侧的边缘。您可以维护对边缘的排序列表,并且不要插入重复的边缘(使用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 cyclen";
else
std::cout << "Graph does not contain cyclen";
return 0;
}
现在它不再报告您的输入周期!
但是,如果我们像这样提供输入(请注意(4,1)
的额外边缘):
1 2 3
1 2 3
2 1 4 5
3 1
4 2 1
5 2
然后它正确地报告一个周期!
相关文章:
- C++图形类指针混淆
- 我的代码中有错误吗?使用BGI图形的C++代码对我不起作用
- 如何在内核C++中使用1920x1080x16M图形或类似的16M颜色?(VGA)
- 这是实现图形的坏方法吗
- 打印 ONNXRUNTIME::图形没有模型
- 提升如何在图形可视化中写入边缘的权重?
- Doxygen - 如何在不生成图形的情况下生成文本调用关系结果
- C++ 中的图形菜单
- 将图形属性与 std::unique_ptr 捆绑在一起
- 从流到邻接列表的向量读取图形
- 替代在python中制作邻接列表与图形问题的字典?(如 C++ 中的 vector<vector<int&g
- 将图形表示为unordered_map<字符串、向量>时拓扑排序错误<string>
- 直接显示手动图形内存泄漏
- Directx 12 :在两个进程之间共享图形内存
- Microsoft C++ 用于图形 API 的 Rest SDK
- 提升图形库:资源受限的最短周期
- 使用查找和联合检测图形中的周期
- 图形:如何使用 DFS 检测无向图中的周期
- BFS可以在图形中找到周期吗?
- 序列化和反序列化具有周期的图形