Graph 如何将图形中的区域转换为图形(节点和边)结构

Graph 如何将图形中的区域转换为图形(节点和边)结构,graph,graph-algorithm,breadth-first-search,Graph,Graph Algorithm,Breadth First Search,我正在解决ioi2007-FLOOD中提出的一个问题,该问题也出现在SPOJ上 我想了很多办法。后来我才知道- Step 0: Converting a region into a node and Step 1: Connecting two nodes with edges only if corresponding regions share at least a segment. Step 2: And then running a BFS on this will simpli

我正在解决
ioi2007-FLOOD
中提出的一个问题,该问题也出现在
SPOJ


我想了很多办法。后来我才知道-

Step 0: Converting a region into a node and 
Step 1: Connecting two nodes with edges only if corresponding regions share at least a segment. 
Step 2: And then running a BFS on this will simplify the problem.
我仍然不能考虑端到端的解决方案,但是我想让我们尝试第0步和第1步。 我也失败了。如果前面有一个图像,我可以很容易地看到区域,但不能通过编程

The input would be end co-ordinate points of segments.
我附上一张图片供参考。
解决这个问题当然有很多不同的方法。一种可能的方法是使用计算机领域的技术。以下两个概念尤其有用:

  • (DCEL):这种数据结构通常用于处理平面图。基本思想是扩展每条边,以保留对边旁边的区域(也称为“面”)的引用

    实现这一点的一种方法是将每个无向边拆分为两个有向边,每个方向一个。然后,可以扩展每个定向边,以保留对其右侧区域的一个引用(从定向边的起始顶点的角度)。此外,扩展每条边以存储对反向边(有时称为“对等”或“双”边)的引用也很有帮助

  • :这种类型的算法在处理平面结构时广泛使用。从概念上讲,它通过在平面上移动“扫描线”来工作,同时保持一些中间结果。每次扫描线击中平面上的对象时,中间结果都会基于该对象进行更新。扫描最终对象后,最终结果应可从中间结果派生

    在更实际的情况下,这通常是通过按输入点的坐标(即首先按y坐标,如果两个点具有相同的y坐标,则按其x坐标)对输入点进行排序来实现的。然后通过在排序点上迭代来完成“扫描”

为了给你更多的参考,我从建筑的角度熟悉这些技术。特别是,如果您进行研究,您会发现它与我在这里描述的方法有一些相似之处(即,它还使用DCEL和扫描内衬)。此外,我还喜欢阅读这篇关于计算几何的文章,它更详细地描述了这些技术

我将在下面的章节中描述如何将这些技术应用于洪水问题。答案的末尾是完整的代码

数据结构 为了避免处理指针,我将主要使用索引来表示对象之间的引用。我使用以下别名来明确给定索引是否应该是顶点、边或面的索引:

使用v_索引t=uint32;
使用e_索引t=uint32;
使用f_索引_t=uint32_t;
constexpr e_index_t NULL_EDGE=0;
constexpr f_index_t外平面=0;
每个顶点存储其位置以及与顶点相关的边。 由于输入图形的边是轴对齐的,因此每个顶点最多可以有四条边。出于这个原因,我使用一个固定大小的数组,四个方向各有四个元素。如果顶点在某个方向上没有边,则使用特殊索引
NULL\u边

struct顶点{
int x;
int-y;
阵列事件;
};
边缘按照DCEL方法存储。每条边都是定向的,并包含对其右侧面的引用和对其对等边的引用:

struct-Edge{
v_指数a;
v_指数b;
e_index_t peer;
f_索引面右;
};
每个面都包含包含该面的边列表:

结构面{
向量边;
};
完整图形包含顶点、边和面的列表:

结构图{ 向量顶点; 向量边; 向量面; }; 算法 构建输入图形后,构建面的基本方法是:

  • 按顶点的坐标对顶点进行排序

  • 初始化一个,它最初将每个顶点指定给它自己的分区。分区用于指示哪些顶点可以彼此接触

  • 迭代排序的顶点。对于每个顶点,检查从该顶点开始的边的方向。对于每个向左或向下的边,检查当前顶点和该边的端点是否在同一分区中(使用union find数据结构的查找操作)

    • 如果是,则边闭合一个内部循环(因为顶点位于同一分区中,如果它们可以彼此接触)。创建一个新的面。从当前边开始,通过始终采用最右侧的后续边,跟随包围面的边。对于每个访问的边,将右转面的DCEL参照设定为指向新创建的面

    • 如果否,请在union find数据结构中连接两个分区,以指示两个顶点可以彼此到达(因此,已知可以从其中一个顶点到达的每个顶点也可以从另一个顶点到达)

假设您实现了一个用于排序顶点的辅助函数
getsorteddverties
,一个实现联合查找数据结构的辅助类
VertexPartition
,以及一个辅助函数
applyFaceRightwards
,该函数通过始终取最右边的后继边沿包围面的边移动,识别人脸的主要程序如下所示:

void图形::createFaceGraph(){
//按坐标对顶点排序
自动索引{getsorteddverties()};
//使用每个顶点的一个分区初始化union find数据结构。
VertexPartition分区(顶点.size());
//扫掠已排序的顶点
用于(v_索引\u t当前:索引){