我有两个数组,每个数组包含同一组整数的不同顺序。每个整数是两个闭合路径在平面中相交的点的标签。这两个阵列被解释为给出沿着平面中的两个闭合路径中的每一个的点的圆形排序(以顺时针顺序),没有特定的起始点。这两条路径彼此相交的次数与数组中的点相同,但路径可能根本不会自相交。如何从这两个数组中确定是否可以在没有自交的平面中绘制两条路径? (整数标签没有固有的含义。)
示例1:A = {3,4,2,1,10,7}和B = {1,2,4,10,7,3}:可能
示例2:A = {2,3,0,10,8,11},B = {10,2,3,8,11,0}:这是不可能的。
通过绘制一个圆圈来尝试,根据A在其周围标记6个点,然后根据B中的顺序尝试连接第二个闭合路径中的6个点,而不穿过您正在绘制的新线。 (我相信无论你是从退出还是进入第一个循环开始,绘制线的可能性/不可能性都没有区别。)你将能够在例1中做到这一点,但不能用例2。
我目前正在使用一种非常复杂的方法,我在一个数组中查看相邻的对,例如在例1中,数组A分为{3,4},{2,1},{10,7},然后我发现数组B中的分组由每种情况下列出的两个成员分区:
{3,4} --> {{1,2}, {10,7}}
{2,1} --> {{4,10,7,3}, {}}
{10,7} --> {{3,1,2,4}, {}}
并检查左侧的每一对是否在其他两行中的每一行中都发现自己位于右侧分区的同一分组中。然后我做同样的事情,偏移一个位置:
{4,2} --> {{10,7,3,1}, {}}
{1,10} --> {{2,4}, {7,3}}
{7,3} --> {{1,2,4,10}, {}}
一切都在这里检查。
但是,在示例2中,该方法表明无法绘制路径。在阵列A的“偏移1”对中,我们发现{10,8}导致阵列B的分区为{{2,3},{11,0}}。但是我们需要11和2在同一个分组中,因为它们是数组A中的下一对点。
这个想法很笨拙,我的实施更加笨拙。我甚至不相信它总是有效。任何人都可以提出一个决定算法吗?目标语言是C,如果重要的话。
编辑:我在这里添加了一个插图:http://imgur.com/TS8xDIk。这里要协调的路径共享点0,1,2和3.在黑色路径上,按顺序访问它们(A = {0,1,2,3})。在蓝色路径上,我们有B = {0,2,1,3}。您可以在左侧看到这是不可能的 - 蓝色路径必须自相交才能完成(或者与黑色路径有其他交叉点,这也是不允许的。)
右侧是相同问题的说明,解释为带边的图形,回应了问题归结为检查平面性的建议。好吧,正如你所看到的,很有可能从这个边集合中形成一个平面图,但是我们无法将图形看作两条带有n个交叉点的闭合路径 - 蓝色路径与另一条路径“交叉”实际上是交叉。这些路径需要在每个节点从内到外交叉,反之亦然,它们不能简单地亲吻和转回。
我希望这可以澄清这个问题,我为第一次缺乏清晰度而道歉。
顺便介绍坐标将是一个完整的红色鲱鱼:任何点都可以给出任何坐标,问题保持不变。从某种意义上说,拓扑不仅仅是几何的。感谢您提供有关如何完成此可行性检查的任何其他建议。
SECOND EDIT显示我当前的代码。就像下面svinja的建议一样,我首先将两个数组减少到0..2n-1的排列。函数的输入是两个数组(包含相同2n整数的不同排序)和这些数组的长度。我是一个没有编程培训的业余爱好者所以我希望你会在编码方法中找到几个不足之处。如果数组A和B处于允许绘制路径的排列关系中,则返回1,否则返回0。
int isGoodPerm(int A[], int B[], int len)
{
int i,j,a,b;
int P[max_len];
for (i=0; i<len; i++)
for (j=0; j<len; j++)
if (B[j] == A[i])
{
P[i] = j;
break;
}
for (i=0; i<len; i++)
{
if (P[i] < P[(i+1)%len])
{
a = P[i];
b = P[(i+1)%len];
}
else
{
a = P[(i+1)%len];
b = P[i];
}
for (j=i+2; j<i+len; j+=2)
if ((P[j%len] > a && P[j%len] < b) != (P[(j+1)%len] > a && P[(j+1)%len] < b))
return 0;
}
return 1;
}
我实际上还在测试这个项目的另一部分,并且只是单独测试了这个部分。当我把它粘贴到更大的代码库并复制了那个版本时,我调整了一些东西 - 我希望我没有引入任何错误。
答案 0 :(得分:0)
我认为长期存在的问题是隐藏真实意图。我可能会遗漏一些东西,但看起来你 需要检查的唯一一件事就是如果可以在没有自相交的情况下绘制数组中的点。我假设你可以将整数映射到实际坐标。如果是这样,您可能会发现相关math.statckexchange网站here提出的解决方案,该网站描述了基于行列式的方法或Bentley-Ottman算法,以便对交叉进行帮助。
答案 1 :(得分:0)
我不确定这是否正确,但由于没有人发布答案,这里是:
我们可以将此问题的任何实例转换为第一个路径为(0, 1, 2, ... N)
的实例。在您的示例2中,这将是(0, 1, 2, 3, 4, 5)
和(3, 0, 1, 4, 5, 2)
。我只提到这个,因为我在代码中进行了这种转换,以简化更多代码。
现在,想象一下第一条路是圆上的点。我想我们可以假设这一点而不失一般性。我还假设我们可以在圆圈的内部或外部开始第二条路径,如果另一条路径也可以在另一条路径上工作。如果我错了,算法肯定是错误的。
所以我们总是首先将第二条路径的第一个和第二个点连接起来,比方说,在外面。如果我们在圆圈上连接彼此不相邻的2个点X和Y ,我们将剩余的点分为A组 - 顺时针从X到Y的那些,以及B组 - 顺时针从Y到X.现在我们记住,A组中的点不能再连接到外部 em 外部的点。
在此之后,我们继续连接第二条路径的第二和第三点,但我们现在在内部。所以我们检查“我们可以在内部连接X和Y吗?”如果我们不能,我们返回false
。如果可以的话,我们再次找到A组和B组,并记住它们中没有一个可以相互连接,但现在位于内部。
现在我们回到外面,我们连接第二条路径的第三和第四点......依此类推。
这是一张图片,展示了它的工作原理,对于您的示例1和示例2:
这是代码(在C#中,但应该很容易翻译):
static bool Check(List<int> path1, List<int> path2)
{
// Translate into a problem where the first path is (0, 1, 2, ... N}
var path = new List<int>();
foreach (var path2Element in path2)
path.Add(path1.IndexOf(path2Element));
var N = path.Count;
var blocked = new bool[N, N, 2];
var subspace = 0;
var currentElementIndex = 0;
var nextElementIndex = 1;
for (int step = 1; step <= N; step++)
{
var currentElement = path[currentElementIndex];
var nextElement = path[nextElementIndex];
// If we're blocked before finishing, return false
if (blocked[currentElement, nextElement, subspace])
return false;
// Mark appropriate pairs as blocked
for (int i = (currentElement + 1) % N; i != nextElement; i = (i + 1) % N)
for (int j = (nextElement + 1) % N; j != currentElement; j = (j + 1) % N)
blocked[i, j, subspace] = blocked[j, i, subspace] = true;
// Move to the next edge
currentElementIndex = (currentElementIndex + 1) % N;
nextElementIndex = (nextElementIndex + 1) % N;
// Outside -> Inside, or Inside -> Outside
subspace = (2 - subspace) / 2;
}
return true;
}
旧答案:
我不确定我是否正确理解了这个问题,但如果我有,我认为这可以减少到planarity testing。我将使用您的示例2作为数字:
从第一个数组创建图G1;它有边2-3, 3-0, 10-8, 8-11, 11-2
从第二个数组创建图G2; 10-2, 2-3, 3-8, 8-11, 11-0, 0-10
创建图G,其边集是G1和G2边集的并集:2-3, 3-0, 10-8, 8-11, 11-2, 10-2, 3-8, 11-0, 0-10
检查G是否为平面。
这是因为我正确地解释了这个问题,即第二条路径不能跨越自身,但也不能越过第一条路径(由于共享顶点,每个顶点不可避免的1个交点除外) )。如果不是这种情况,那么示例2 does have solutions(注意第二条路径如何穿过11-2和8-10边)。 击>