루프 감지-그런 종류가 아닙니다!


24

이 과제의 목표는 루프로 둘러싸인 방향과 면적을 찾는 것입니다.

입력:

다음 문자로 구성된 직사각형 그리드 ^v<>

(선택적으로 접두사, 접미사 및 선택한 구분 문자를 사용하여 그리드 자체 앞에 10 진수로 그리드의 크기를 지정할 수도 있습니다.)

그리드 의 루프 는 앞에서 언급 한 문자 집합으로, 다음 문자를 가리키고 다음 문자를 가리키며 결국 첫 문자를 다시 가리 킵니다. 예를 들면 다음과 같습니다.

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

왼쪽 그리드는 샘플 입력입니다. 오른쪽 그리드는 루프가 격리 된 것입니다.

입력 그리드는 루프가 전혀 없거나 하나의 루프를 포함합니다. 그리드에 둘 이상의 루프가 포함 된 경우에 대해 걱정할 필요가 없습니다.

산출:

그리드에 루프가 없으면 output을 출력하십시오 X.

격자에 서로를 가리키는 두 개의 화살표가 포함되어 있으면 출력 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 폐 루프를 형성하지 않습니다.
Martin Ender

@ MartinBüttner 바깥 쪽 끝이 서로 연결되어 있다고 상상해보십시오.
ghosts_in_the_code

4
@ghosts_in_the_code 그런 다음 한쪽 중 하나가 다른 쪽을 만나기 위해 돌아야합니다. 이 경우 시계 방향 또는 시계 반대 방향으로 진행되는지 여부를 표시하기 위해 원으로 펼칠 수있는 교차로 자유 루프가 나타납니다. 간단한 테스트는 루프의 가장 아래쪽 점을보고 왼쪽 또는 오른쪽으로 가고 있는지 확인하는 것입니다 (그리드의 경우 해당 점은 고유하지 않지만 가장 오른쪽 아래의 셀을 볼 수 있음) 루프하고 왼쪽 또는 위쪽으로 진행되는지 확인하십시오).
Martin Ender

답변:


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(전체 너비)에 대한 맵을 만듭니다. 가장자리에 있거나 W더 많은 것을 단순화하기 위해 +1 (색인 인 경우 ).

이 작업을 수행하는 동안 루프의 '마지막'요소가 갖는 방향 (즉, 루프의 요소가있는 마지막 행의 루프의 마지막 요소)도 찾습니다. 이 요소는 "<"또는 "^"이어야하며, 루프의 클럭 (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.