ループ検出-そんなことはありません!


24

この課題の目標は、ループで囲まれた方向と領域を見つけることです。

入力:

これらの文字のみで構成される長方形のグリッド: ^v<>

(オプションで、選択した接頭部、接尾部、および分離文字を使用して、グリッド自体の前に10進数でグリッドの寸法を指定することもできます。)

ループグリッドでは次を指し、次の1つの点は、最終的に最初の文字に戻っ指し示すように前述の文字の集合です。例えば:

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

左のグリッドはサンプル入力です。右側のグリッドは分離されたループです。

入力グリッドには、ループがまったく含まれないか、1つのループが含まれます。グリッドに複数のループが含まれる場合について心配する必要はありません。

出力:

グリッドにループが含まれていない場合は、を出力しますX

グリッドが互いに指し示す2つの矢印を含む場合、output 0

グリッドに反時計回りのループが含まれている場合、境界線を含め、ループで囲まれた文字をカウントします。その番号を出力します。

グリッドに時計回りのループが含まれている場合、反時計回りのループと同じプロセスに従いますが、その数値の負数を出力します。たとえば、上記の入力グリッドの出力は-11次のとおりです。10はループ自体からのもので、1はループで囲まれた文字からのものです。

これはです。最短のコードが優先されます。

テストケース:

<<^
^>v
^v<

出力X

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

出力0

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

出力-15

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

出力20


4
なぜダウン投票なのですか?質問は私には問題ありません。
xnor

ループが時計回りかどうかをどのように判断しますか?たとえば、Google画像検索で「二重らせん迷路」を検索します。パスの実行方法をどのように判断しますか?以下に例を示します。
ghosts_in_the_code

@ghosts_in_the_codeこれは閉ループを形成しません。
マーティンエンダー

@MartinBüttner外側の2つの端が互いに接続することを想像してください。
ghosts_in_the_code

4
@ghosts_in_the_code次に、一方の端がもう一方に会うために向きを変える必要があります。その場合、交差していないループが得られます。これは、時計回りに進むか反時計回りに進むかを示すために円に展開できます。簡単なテストは、ループの一番下のポイントを見て、それが左または右に行くかどうかを確認することです(グリッドの場合、そのポイントは一意ではありませんが、右下のセルを見ることができますループし、左または上に行くかどうかを確認します)。
マーティンエンダー

回答:


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)からそれ自体-1(ループ上にあることを意味する)、またはW(幅全体)へのマップを作成しますそれが端にある場合(または、W物事をさらに単純化するために+1(indexにある))。

これを行う間、ループの「最後の」要素が持つ方向(つまり、ループの要素が含まれる最後の行のループの最後の要素)も見つけます。この要素は「<」または「^」でなければならず、これはループのクロックネス(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
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.