循环检测-不是那种!


24

这项挑战的目标是找到一个回路所包围的方向和区域。

输入:

完全由以下字符组成的矩形网格: ^v<>

(可选地,您还可以在网格本身之前为网格指定尺寸,以十进制表示,并带有您选择的前缀,后缀和分隔符。)

在网格是一组在上述的字符,使得一个指向下一个的,指向在第一个字符的下一个,最终指回。例如:

<>>v>     >>v 
^^<>v     ^ >v
>^<<<     ^<<<
>^<v>         

左边的网格是样本输入;正确的网格是隔离的循环。

输入网格将不包含任何循环,也可以包含一个循环。您不必担心网格包含多个循环的任何情况。

输出:

如果网格不包含循环,则输出X

如果网格包含两个指向彼此的箭头,则输出0

如果网格包含一个逆时针循环,请计算循环所包围的字符,包括边界。输出该号码。

如果网格包含顺时针循环,请对逆时针循环执行相同的过程,但输出该数字的负数。例如,上述输入网格的输出为-11:10来自循环本身,而1来自循环所包围的字符。

这是。最短的代码胜出。

测试用例:

<<^
^>v
^v<

输出X

<<<<
><<<
>>^>

输出0

<>^^<
>>>v>
<^^>v
<^>>v
>^<<<

输出-15

v<<<<
>v>>^
v<^<<
>>>>^

输出20


4
为什么要下票?这个问题对我来说很好。
xnor 2015年

您如何确定循环是否为顺时针?例如,在Google图片上搜索“双螺旋迷宫”。您如何确定路径的运行方式?是一个例子。
ghosts_in_the_code 2015年

@ghosts_in_the_code不构成闭环。
马丁·恩德

@MartinBüttner想象一下外部的两端互相连接。
ghosts_in_the_code 2015年

4
@ghosts_in_the_code然后,其中一个目的必须转过来与另一个见面。在这种情况下,您将获得一个无交集的循环,该循环可以展开为一个圆形以显示它是顺时针还是逆时针旋转。一个简单的测试是查看循环的最底部点,并检查它是否向左或向右移动(对于网格,该点不是唯一的,但是您可以查看循环的最右下角的单元格循环并检查它是向左还是向上)。
马丁·恩德

Answers:


4

C#,604字节

完整的程序,接受来自STDIN的输入(以行分隔的布局,无尺寸),输出至STDOUT。

using C=System.Console;class P{static void Main(){int w=0,W,i,j,t,k,l,c;string D="",L;for(;(L=C.ReadLine())!=null;D+=L)w=L.Length;var R=new[]{-1,0,1,w,-w};L="X";for(W=i=D.Length;i-->0;){var M=new int[W];for(k=j=i;i>0;){M[j]=++k;t=j+R[c=D[j]%5];if(t<0|t>=W|c<3&t/w!=j/w|c>2&t%w!=j%w)break;j=t;if((l=M[j])>0){var J=new int[W+1];System.Func<int,int>B=null,A=s=>J[s]<0?0:J[k=B(s)]=k==W?k:i;B=x=>J[x]==x?x:B(J[x]);for(i=J[W]=W;i>0;)J[--i]=M[i]<l?i%w<1|i%w>w-2|i<w|i>W-w?W:i:-1;for(;i<W;)if(J[++i]<0)l=D[i]%5/2-1;else{A(i-1);if(i>w)A(i-w);}for(c=W;i-->0;L=""+(c>2?c:0)*l)c-=J[i]<0?0:B(i)/W;}}}C.WriteLine(L);}}

该程序的工作方式是先读取布局,不用说,然后遍历每个单元格。然后,我们从每个单元格运行一个“蛇”,跟随箭头,直到它越过边缘或碰到自身。如果它碰到了自己,那么我们知道我们已经找到了一个循环(或其中的一个“>”事物),并且它还知道循环中有多少条蛇。

知道有一个循环后,我们知道循环中有哪些像元,然后从每个像元(出于某种原因,为+1)到其自身-1(表示在循环中)或W(整个宽度)创建一个映射如果它在边缘(或+1(位于index处,W以简化操作))。

在执行此操作的同时,我们还会找到循环的“最后一个”元素所具有的方向(即,最后一行上的循环的最后一个元素具有来自循环的元素)。该元素必须为“ <”或“ ^”,这告诉我们循环的时脉(CW / CCW)(转换为-1 / + 1)。

然后,我们执行分离集传递,将循环外的所有元素分配给该W集。然后,我们减去其中的多少,W以获取循环中和循环中包含的数字。如果该数字小于3,则将其替换为0。将其乘以时钟频率,将其设置为结果,然后以某种方式从for循环中逸出,在该循环中输出结果。

但是,如果以上大多数操作都没有发生(因为没有蛇发现过),那么结果将保留为“ X”,并输出。

using C=System.Console;

class P
{
    static void Main()
    {
        int w=0, // width
        W, // full length
        i, // used for iterating over all the cells
        j, // keeps track of where the snake as got to
        t, // t is next j
        k, // how far along the snake we are, kind of
        // later on, k is used as temp for A
        l, // stores a threshold for how far along the snake the loop starts
        // later on, l stores the last seen pointer - this tells us the clockness
        c; // the translated direction
        // later on, c is a backwards-count

        string D="", // D is the map
        L; // used for reading lines, and then storing the result

        // might not be the best yay of doing this
        for(;(L=C.ReadLine())!=null; // read a line, while we can
            D+=L) // add the line to the map
            w=L.Length; // record the width

        var R=new[]{-1,0,1,w,-w}; // direction table (char%5) - might be able to replace this array with some bit bashing/ternary

        L="X"; // can't seem to fit this in anywhere... (don't strictly need to re-use L)
        for(W=i=D.Length;i-->0;) // for each cell, we send a 'snake' to try to find the loop from that cell
        {
            var M=new int[W]; // stores how far along the snake this point is

            for(k=j=i; // k's value doesn't really matter, as long as it's not stupidly big
                i>0;) // the i>0 check is just for when we return (see comment at the end of the code)
            {
                M[j]=++k; // store snake point and advance distance

                t=j+R[c=D[j]%5]; // t is position after move (translate <>v^ to 0234 (c is direction))
                //c=D[j]%5; // translate <>v^ to 0234 (c is direction)
                //t=j+R[c]; // t is position after move
                if(t<0|t>=W|c<3&t/w!=j/w|c>2&t%w!=j%w)
                    break; // hit an edge - will always happen if we don't find a loop - give up on this snake
                j=t; // move to new position

                if((l=M[j])>0) // we've been here before...
                {
                    // disjoint sets (assign all the edges to one set, assign all the ones on the line to another set, do adjacent disjoint, return size-outteredge (minus if necessary)
                    var J=new int[W+1]; // looks like we can reuse M for this

                    System.Func<int,int>B=null,
                    // whatever s points at should point to i, unless s points to W, in which case it should keep point to W
                    A=s=>J[s]<0?0:J[k=B(s)]=k==W?k:i;
                    // read the value this points to
                    B=x=>J[x]==x?x:B(J[x]);

                    for(i=J[W]=W;i>0;)
                        J[--i]=M[i]<l? // if we are not part of the loop
                            i%w<1|i%w>w-2|i<w|i>W-w? // if we are on the edge
                                W: // on the edge
                                i: // not on the edge
                             -1; // this is on the loop

                    // now fill in
                    // we don't have to worry about wrapping, the important bit being an un-wrapping closed loop
                    // i = 0
                    for(;i<W;)
                        if(J[++i]<0) // we are on the loop
                            l=D[i]%5/2-1; // last one must be ^(4) or <(0)
                        else{ // can probably crush this into an l returning l assigning term (with if above)
                            A(i-1);
                            if(i>w)
                                A(i-w);
                        }

                    // now count the number of non-edges
                    for(c=W; // assume everything is a non-edge
                        i-->0;
                        L=""+(c>2?c:0)*l) // set output to be number of non-edges * clockness (or 0 if too few)
                        c-=J[i]<0?0:B(i)/W; // subtract 1 if an edge (B(i) is W), othewise 0

                    // at this point, i is 0, so we will fall out of all the loops
                }
            }
        }

        C.WriteLine(L); // output result
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.