Phát hiện vòng lặp - không phải là loại đó!


24

Mục tiêu của thử thách này là tìm hướng và khu vực được bao quanh bởi một vòng lặp.

Đầu vào:

Một lưới hình chữ nhật bao gồm hoàn toàn các ký tự này: ^v<>

(Tùy chọn, bạn cũng có thể được cung cấp các kích thước của lưới trước khi lưới chính ở dạng thập phân với tiền tố, hậu tố và ký tự phân cách bạn chọn.)

Một vòng lặp trong lưới là một tập hợp các ký tự đã nói ở trên sao cho một điểm tiếp theo, chỉ tới điểm tiếp theo, cuối cùng quay lại ký tự đầu tiên. Ví dụ:

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

Lưới bên trái là đầu vào mẫu; lưới bên phải là vòng lặp bị cô lập.

Lưới đầu vào sẽ không chứa vòng lặp nào cả hoặc một vòng lặp; bạn không phải lo lắng về bất kỳ trường hợp nào trong đó lưới chứa nhiều hơn một vòng lặp.

Đầu ra:

Nếu lưới không chứa vòng lặp, đầu ra X.

Nếu lưới chứa hai mũi tên chỉ vào nhau, đầu ra 0.

Nếu lưới chứa vòng lặp ngược chiều kim đồng hồ, hãy đếm các ký tự được bao quanh bởi vòng lặp, bao gồm cả đường viền. Đầu ra số đó.

Nếu lưới chứa vòng lặp theo chiều kim đồng hồ, hãy làm theo quy trình tương tự cho vòng lặp ngược chiều kim đồng hồ, nhưng xuất ra âm của số đó. Chẳng hạn, lưới đầu vào ở trên sẽ có đầu ra là -11: 10 đến từ chính vòng lặp và 1 từ ký tự được bao quanh bởi vòng lặp.

Đây là . Mã ngắn nhất sẽ thắng.

Các trường hợp thử nghiệm:

<<^
^>v
^v<

Đầu ra X.

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

Đầu ra 0.

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

Đầu ra -15.

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

Đầu ra 20.


4
Tại sao các downvote? Câu hỏi có vẻ tốt với tôi.
xnor

Làm thế nào để bạn xác định nếu một vòng lặp theo chiều kim đồng hồ hay không? Ví dụ: tìm kiếm "mê cung xoắn ốc kép" trên Google Images. Làm thế nào để bạn xác định con đường nào đang chạy? Đây là một ví dụ.
ghosts_in_the_code

@ghosts_in_the_code Điều đó không tạo thành một vòng khép kín.
Martin Ender

@ MartinBüttner Hãy tưởng tượng hai đầu ngoài để kết nối với nhau.
ghosts_in_the_code

4
@ghosts_in_the_code Sau đó, một trong hai đầu sẽ phải quay lại để gặp người kia. Trong trường hợp đó, bạn có được một vòng lặp tự do giao nhau có thể được mở ra thành một vòng tròn để hiển thị xem nó đi theo chiều kim đồng hồ hay ngược chiều kim đồng hồ. Một thử nghiệm đơn giản là xem xét điểm dưới cùng của vòng lặp và kiểm tra xem nó đi sang trái hay phải (trong trường hợp lưới, điểm đó không phải là duy nhất, nhưng bạn có thể nhìn vào ô dưới cùng bên phải của vòng lặp và kiểm tra xem nó đi sang trái hay lên).
Martin Ender

Câu trả lời:


4

C #, 604 byte

Hoàn thành chương trình, chấp nhận đầu vào (bố cục phân cách dòng, không có kích thước) từ STDIN, xuất ra 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);}}

Chương trình hoạt động bằng cách đọc đầu tiên trong bố cục, không cần phải nói, và sau đó lặp đi lặp lại trên mỗi ô. Sau đó chúng tôi chạy một "con rắn" từ mỗi ô, theo mũi tên cho đến khi nó chạy ra khỏi rìa hoặc chạy vào chính nó. Nếu nó chạy vào chính nó, thì chúng ta biết rằng chúng ta đã tìm thấy một vòng lặp (hoặc một trong những thứ "> <" đó) và nó cũng biết bao nhiêu con rắn trong vòng lặp.

Khi chúng tôi biết chúng tôi có một vòng lặp, chúng tôi biết các ô nào trên vòng lặp và chúng tôi tạo một bản đồ từ mỗi ô (+1, vì lý do) cho chính nó, -1(có nghĩa là trên vòng lặp) hoặc W(toàn bộ chiều rộng) nếu nó ở cạnh (hoặc +1 (nằm trong chỉ mục W) để đơn giản hóa mọi thứ hơn nữa).

Trong khi chúng ta thực hiện điều này, chúng ta cũng tìm thấy hướng mà phần tử 'cuối cùng' của vòng lặp có (nghĩa là phần tử cuối cùng của vòng lặp trên hàng cuối cùng có các phần tử từ vòng lặp trên nó). Phần tử này phải là "<" hoặc "^" và điều này cho chúng ta biết độ đồng hồ (CW / CCW) của vòng lặp (được dịch thành -1 / + 1).

Sau đó, chúng tôi thực hiện một lượt vượt qua tập hợp, nó gán tất cả các phần tử nằm ngoài vòng lặp cho Wtập hợp. Sau đó, chúng tôi trừ đi có bao nhiêu trong số này Wđể có được số có trong và trong vòng lặp. Nếu con số này nhỏ hơn 3, chúng tôi thay thế nó bằng 0. Chúng tôi nhân số này với độ đồng hồ, đặt nó làm kết quả và bằng cách nào đó thoát khỏi các vòng lặp for, trong đó kết quả là đầu ra.

Tuy nhiên, nếu hầu hết những điều trên không bao giờ xảy ra (vì không có con rắn nào tự tìm thấy), thì kết quả vẫn là "X", và điều đó đã được đưa ra.

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
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.