몇 개의 구멍?


17

도전

도형을 그래픽으로 입력하면 몇 개의 구멍이 있는지 확인하십시오.

중복되지 않음

이 질문은 Count Islands의 복제본으로 표시되었습니다 . 이 도전은 Count Island 도전과는 다르다고 생각합니다. 왜냐하면이 도전에서는 경계에 닿는 블록을 제거하는 방법을 알아야하기 때문입니다.

입력

입력은 여러 줄로 된 입력, 여러 줄 문자열, 문자열 배열 또는 문자 배열로 제공됩니다. 모양을 나타냅니다. 모양은 가장자리로 연결된 한 조각에만 있어야합니다. 입력 방법을 지정하십시오.

산출

출력은 모양에 몇 개의 구멍이 있는지 나타내는 단일 정수입니다. 후행 줄 바꿈은 허용되지만 다른 선행 또는 후행 공백은 허용되지 않습니다. 즉, 출력은 정규식과 일치해야합니다 ^\d+\n?$.

구멍이 무엇입니까?

이들은 단일 구멍입니다.

####
#  #
#  #
####

####
#  #
# ##
###

#####
# # #
#   #
#####

이들은 구멍이 아닙니다 :

########
########
#   ####
#   ####
# ######
#       
########

###
#  
###

##########
#         
# ########
# #      #
# # #### #
# #   ## #
# ###### #
#        #
##########

간격이 바깥 쪽 가장자리와 결합하면 구멍이 아닙니다.

테스트 사례

#####
# # # -> 2
#####

#####
#    
# ### -> 1
# # #
#####

####
## # -> 1 (things are connected by edges)
# ##
####

###
### -> 0 (You must handle shapes with no holes, but input will always contain at least one filled space)
###

'#'대신 공백 대신 모든 문자를 사용할 수 있습니다.

목표 점수 기준

점수는 프로그램의 바이트 수로 제공됩니다.

승리

우승자는 4 월 4 일까지 가장 낮은 점수로 제출됩니다.



2
###|# #|## 테스트 사례로 추가 할 수 있습니까? 그럴까요 0?
— Martin Ender



@SIGSEGV 지적 해 주셔서 감사합니다. 그러나 나는이 도전에 다른 도전과는 다른 자신의 게시물을 보증하기에 충분히 다른 중요한 구성 요소가 있다고 생각합니다 (차이를 편집했습니다). 의견을 보내주세요. 필요한 경우 채팅으로 토론을 시작하고 싶을 수도 있습니다.
— 하이퍼 뉴트리노

답변:


12

MATLAB / 옥타브, 18 바이트

@(g)1-bweuler(g,4)

온라인으로 사용해보십시오!

논리 행렬을 입력으로 사용하는 익명 함수입니다. 개체는 true지정된 연결성을 가진 항목 으로 구성되며 빈 공간은 false항목입니다.

bweuler 그런 다음 해당 행렬로 표시되는 이진 이미지의 오일러 수, 즉 객체 수에서 홀 수를 뺀 값을 계산합니다.


8

Mathematica, 59 57 바이트

1/.ComponentMeasurements[#,"Holes",CornerNeighbors->0>1]&

내장되어 있습니다. 1s (벽) 및 0s (구멍)의 2D 행렬로 입력을 받습니다. 편의상이 입력 형식의 모든 테스트 사례는 다음과 같습니다.

{{{1,1,1,1},{1,0,0,1},{1,0,0,1},{1,1,1,1}},
 {{1,1,1,1},{1,0,0,1},{1,0,1,1},{1,1,1,0}},
 {{1,1,1,1,1},{1,0,1,0,1},{1,0,0,0,1},{1,1,1,1,1}},
 {{1,1,1,1,1,1,1,1},{1,1,1,1,1,1,1,1},{1,0,0,0,1,1,1,1},{1,0,0,0,1,1,1,1},{1,0,1,1,1,1,1,1},{1,0,0,0,0,0,0,0},{1,1,1,1,1,1,1,1}},
 {{1,1,1},{1,0,0},{1,1,1}},
 {{1,1,1,1,1,1,1,1,1,1},{1,0,0,0,0,0,0,0,0,0},{1,0,1,1,1,1,1,1,1,1},{1,0,1,0,0,0,0,0,0,1},{1,0,1,0,1,1,1,1,0,1},{1,0,1,0,0,0,1,1,0,1},{1,0,1,1,1,1,1,1,0,1},{1,0,0,0,0,0,0,0,0,1},{1,1,1,1,1,1,1,1,1,1}},
 {{1,1,1,1,1},{1,0,1,0,1},{1,1,1,1,1}},
 {{1,1,1,1,1},{1,0,0,0,0},{1,0,1,1,1},{1,0,1,0,1},{1,1,1,1,1}},
 {{1,1,1,1},{1,1,0,1},{1,0,1,1},{1,1,1,1}}}

대체 솔루션, 59 바이트

이것이 내 원래의 접근법이었습니다. 또한 구성 요소 관련 내장 기능을 기반으로하지만 구멍을 직접 계산하지는 않습니다 (홀 자체를 구성 요소로 취급하는 대신).

Max@*MorphologicalComponents@*DeleteBorderComponents@*Image

위와 동일한 입력 형식을 취하지 만 0s와 1s 의 역할이 서로 바뀝니다.

이것을 Image첫 번째 로 변환 해야하는 이유 는 그렇지 않으면 Mathematica는 모든 1셀을 단일 구성 요소의 일부로 간주 하기 때문입니다 (매트릭스를 구성 요소 레이블 매트릭스로 취급하기 때문에). 따라서, 있다면1 셀이 여백과 경계를 이루면 셀이 삭제됩니다. 때 DeleteBorderComponents대신 이미지를 사용, 그것은 구성 요소를 찾을 수 암시 적 연결 체크를 할 것입니다.

또는 MorphologicalComponents first를 호출 하여 입력을 적절한 레이블 매트릭스로 바꿀 수 있지만 DeleteBorderComponents두 번째로 더 이상 최대 구성 요소 레이블이 구성 요소 수에 해당한다고 더 이상 보장되지 않습니다 (작은 구성 요소를 삭제할 수 있기 때문).


5
실제로 Mathematica는 모든 것을위한 내장 기능을 갖추고 있습니다.
— Mr. Xcoder

3
@ Mr.Xcoder 좋은 도전 아이디어가 있습니다. Mathematica에없는 도전을 찾으십시오.
— HyperNeutrino

@HyperNeutrino 좋은 생각이지만, Mathematica 사용자는 불행히도 그것을 많이 삭감 할 것이라고 생각합니다. 커뮤니티가 잘 반응 할 것인지 모르겠습니다 ... =]
— Mr. Xcoder

1
@HyperNeutrino, 아마도 그것도 내장되어있을 것입니다 :-)
— Brian Minton

@BrianMinton Haha. Mathematica에는이라는 내장이있을 것입니다 GenerateBuiltin. 빌트인이없는 챌린지에 대해 빌트인을 생성합니다. 또한, 나는 그래서 당신이 원하는 경우에,의이 토론을 계속하자, 마틴 청산의받은 편지함에 대한 나쁜 생각 여기
— HyperNeutrino

4

펄 5 , 154 바이트

152 바이트의 코드 + -p0플래그의 경우 2 바이트

s/^ | $/A/gm;s/^.*\K | (?=.*$)/A/&&redo;/.*/;$@="@+"-1;for$%(A,X){$~="(.?.?.{$@})?";(s/$%$~ /$%$1$%/s||s/ $~$%/$%$1$%/s)&&redo}s/ /X/&&++$\&&redo}{$\|=0

온라인으로 사용해보십시오!

나는 코드가 매우 설명 적이라고 생각합니다.


이해해야 할 설명이 필요한 경우 간단한 입력으로 프로그램에서 수행 한 몇 가지 변환 단계는 다음과 같습니다. 같습니다 여기 나옴). 다음과 같은 설명이 있습니다.

######
#     
# ####
# # #
#### #
######

######
# ㅏ
# ####
# # #
#### #
######

######
#AAAAA
#ㅏ####
#ㅏ# #
#### #
######

######
#AAAAA
#ㅏ####
# A # X #
#### #
######

######
#AAAAA
#ㅏ####
# A # XX #
####엑스#
######

먼저 s/^ | $/A/gm;s/^.*\K | (?=.*$)/A/&&redo테두리의 공백 (왼쪽 / 오른쪽의 첫 번째 정규 표현식, 아래쪽 / 위쪽의 두 번째 정규 표현식)을 A(나는 그 문자를 매우 임의적으로 선택합니다)로 바꿉니다.
그런 다음 너비를 사용하여 모양을 얻습니다 /.*/;$@="@+"-1;.
이제,에 연결된 모든 공간을로 교체하고 싶습니다 A. A(공백이에 연결되어 있으면 A구멍의 일부가 될 수 없기 때문에.에 의해 수행됩니다 for$%(A,X){(s/$%(.?.?.{$@})? /$%$1$%/s||s/ (.?.?.{$@})?$%/$%$1$%/s)&&redo}. (이것이 완료되었음을 알 수 있습니다) 에 대한 일단 A의와 하나 X의 -에 대한 설명 X)를 넣고 두 정규식은 여기에 있습니다. s/$%(.?.?.{$@})? /$%$1$%/s의 우측 또는 하단에있는 공백 거래 A합니다. s/ (.?.?.{$@})?$%/$%$1$%/s상단에 공백 또는 왼쪽은A .
이 시점에서 문자열에 남은 공간은 구멍의 일부입니다.
여전히 공백이 있지만 반복합니다
.-구멍이 얼마나 있는지 알기 위해 공백을 X( s/ /X/)로 바꾸고 구멍 카운터 ( $\++)를 늘리고 전체 프로그램을 다시 실행하십시오 (실제로는 for루프 를 다시 실행하고 싶습니다) 그러나 전체 프로그램을 다시 실행하는 데 적은 바이트가 필요합니다).
- 다음에, for루프 (A)에 접속되어있는 모든 공간을 대체 할 X로모그래퍼을 X가 동일한 구멍의 일부로서.
마지막에 $\|=0구멍이없는 경우 0빈 문자열 대신 a 가 인쇄되도록합니다. 그리고 플래그 $\덕분에 암시 적으로 인쇄됩니다 -p.


4

파이썬 2, 282 바이트

대각선 터치를 처리하기 위해 +100 TT_TT (실제로 필요합니까?)
@Rod 안내 덕분에 -119

온라인으로 사용해보십시오 . 문자 '#'과 공백 배열을 입력으로받습니다.

A=input()
c=0
X=len(A[0])-1
Y=len(A)-1
def C(T):
 x,y=T
 global g
 if A[y][x]<'#':
    if y<1or y==Y or x<1or x==X:g=0
    A[y][x]='#';map(C,zip([x]*3+[min(x+1,X)]*3+[max(x-1,0)]*3,[y,min(y+1,Y),max(y-1,0)]*3))
while' 'in sum(A,[]):i=sum(A,[]).index(' ');g=1;C((i%-~X,i/-~X));c+=g
print c

첫 공백을 검색하여 비어 있지 않은 것으로 표시합니다 ( '#'). 빈 셀을 채우면서 주변의 모든 것을 재귀 적으로 확인하십시오. 현재 "구멍"의 빈 셀이 경계 카운터에있는 것으로 보이면 변경되지 않습니다. 공백이 더 이상 없을 때까지 프로세스를 반복하십시오.


1
sum(A,[])납작하게 사용할 수 있습니다
— Rod

1
또한 이 답변을 확인할 수 있으며 동일한 재귀 논리를 가지며 첫 번째 줄의 "이름 바꾸기"와 같은 다른 트릭도 있습니다.
— Rod

합계와 @로드 트릭은 매우 좋습니다, 감사합니다. 나는 지금이 추악함없이 8 방향을 모두 얻기 위해 노력하고 있습니다. 당신의 대답이 도움이 될 것입니다. 그 후에 업데이트하겠습니다
— Dead Possum

내 대답에 따르면 적은 바이트를 사용하기 위해 목록 이해 내에서 재귀 함수를 호출했지만 현재 셀이 테두리에 속하는지 확인하기 위해 목록 길이를 확인할 수 있습니다 (목록의 내용은 많을 것입니다) Nones, 그러나 그것은 관련이 없습니다)
— Rod

1
당신은에 풀고 목록을 사용할 수 있습니다 x=T[0];y=T[1]-> x,y=T, (아마도) 당신이 선언 할 필요가 없습니다 g=1셋째 줄에, 당신은 사용할 수 있습니다 <또는 >(가 소요됩니다 문자열을 비교하기 위해 ord()각 문자의 값을) 바꿀 수 있도록 A[y][x]!='#'함께 A[y][x]<'#'때문에 ' '<'#'.
— Rod

3

파이썬 2 233 225 222 바이트

math_junkie : -8 바이트

부울 / 정수의 2 차원 배열을 입력으로 취합니다 (0/1).

s=input()
o=[-1,0,1]
m=lambda x,y:0if x in[-1,len(s[0])]or y in[-1,len(s)]else 1if s[y][x]else(s[y].__setitem__(x,1),all([m(x+a,y+b)for a in o for b in o]))[1]
e=enumerate
print sum(m(x,y)-c for y,l in e(s)for x,c in e(l))

온라인으로 사용해보십시오!

형식화 된 버전 :

s = input()
o = [-1, 0, 1]
m = lambda x,y:
    0 if x in [-1, len(s[0])] or y in [-1, len(s)]
      else
        1 if s[y][x]
          else
            (s[y].__setitem__(x, 1),
             all([m(x + a, y + b) for a in o for b in o]))[1]
e = enumerate
print sum(m(x, y) - c for y, l in e(s) for x, c in e(l))

1
당신과 함께 몇 바이트를 저장할 수 있습니다 print sum(m(x,y)...대신 a=과print a
— 수학 마약 중독자

1
또한 약간의 공백 골프 : TIO
— math junkie

1

C # 7, 364 바이트

이것에 만족하는 것보다 ... 다른 누군가가 그것을 분류 할 수 있습니다 ... 나중에 에너지가 있으면 첫 번째 루프를 뒤집어 그 경계 검사를 줄이는 데 도움이되는지 확인하십시오.

using C=System.Console;class P{static void Main(){string D="",L;int W=0,H=0,z;for(;(L=C.ReadLine())!=null;H+=W=L.Length)D+=L;int[]S=new int[H*9];int Q(int p)=>S[p]<p?Q(S[p]):p;void R(int r)=>S[Q(r+=z)]=S[r]>0?z:0;for(z=H;z-->0;)if(D[z]<33){S[z]=z;R(1);R(W);R(W+1);R(W-1);}for(;++z<H;)S[Q(z)]*=z>H-W-2|z%W<1|z%W>W-2?0:1;for(;W<H;)z+=Q(W)<W++?0:1;C.WriteLine(z-H);}}

온라인으로 사용해보십시오

완전한 프로그램, 표준 입력, 표준 출력으로의 입력을 받아들입니다. 불연속 세트를 사용하여 임시 구멍을 결정하고 테두리를 터치 할 때 (가장자리에 약간의 영향을 미침).

형식화 및 주석 처리 된 코드 :

using C=System.Console;

class P
{
    static void Main()
    {
        string D="", // the whole map
            L; // initally each line of the map, later each line of output

        // TODO: some of thse might be charable
        int W=0, // width, later position
            H=0, // length (width * height)
            z; // position, later counter

        // read map and width
        for(;(L=C.ReadLine())!=null; // read a line, while we can
                H+=W=L.Length) // record the width, and increment height
            D+=L; // add the line to the map

        // disjoint sets
        int[]S=new int[H*9]; // generousness (relieve some bounds checking)
        // note that S[x] <= x, because we call R with decending values of z

        // returns whatever p points to
        int Q(int p)=>S[p]<p?Q(S[p]):p;
        // points whatever r points to at z if r is empty
        void R(int r)=>S[Q(r+=z)]=S[r]>0?z:0; // note that is never called when z=0

        // fill out disjoint sets
        for(z=H;z-->0;)
            if(D[z]<33) // if cell is empty
            {
                S[z]=z; // point it at itself

                // point the things next  to z at z
                R(1);
                R(W);
                R(W+1);
                R(W-1);
            }

        // zero sets which are against the left, bottom, or right edges
        for(;++z<H;)
            S[Q(z)]*=z>H-W-2|z%W<1|z%W>W-2?0:1; // TODO?: this suggests inverting the first loop (NOTE: would break S[x]<=x)

        // starting from the second row, count all the sets that point to this cell (ignores any non-zeros pointing to first row)
        for(;W<H;)
            z+=Q(W)<W++?0:1;

        C.WriteLine(z-H);
    }
}

Func<List<string>, int>보풀과 콘솔 물건을 제거하려면 로 변환하십시오 . 그러나 로컬 기능이 있으므로 기능에 포함하지 못할 수도 있습니다. 메소드로 컴파일 할 수 있습니다 int h(string[] s) { }.
— TheLethalCoder

여기에 단순화 할 수있는 것이 더 많이있을 것입니다 ...
— TheLethalCoder

@TheLethalCoder 나는 이것을 다른 형식으로 변환하지 않고 함수로서의 답변을 좋아하지 않습니다 (당신이 말한 것처럼 람다 일 필요는 없습니다). 그래 ... 모든 것이 부풀어 오른 느낌이지만 ... 나는 그것을 바꾸는 동안 좋은 시간을 보냈고 실질적인 진전을 이루지 못했습니다. 더 짧은 버전을 제출해주세요.이 버전보다 적습니다.
— VisualMelon

더 이상 필요하지 않기 때문에 메소드로 변환하고 모든 콘솔 항목을 제거하면 50-100 바이트가 줄어들 것입니다 (추측하지만 많이 노크합니다).
— TheLethalCoder

실제로 @TheLethalCoder; 나는 함수를 답변으로 제출하는 것을 좋아하지 않습니다. 표준 입력은 꽤 표준이며 '완전한 프로그램'은 어디서나 쉽게 컴파일하고 실행할 수 있습니다. 형식화되지 않은 람다를 시작하지 마십시오 . 분명히, 경쟁 Java 답변이 있다면 표준을 약간 느슨하게해야합니다 ...
— VisualMelon

1

달팽이 , 48 바이트

!{\ z`+~}\ {t\ z!.!~=((lu|u.+r)!(.,~},!{t\ z!.!~

언 골프 드 :

!{
    (\   z)+
    ~
}
\ 
{
    t \ 
    z !.!~
    ={
        (lu|u.+r)
        !(.,~)
    }
},
!{
    t \ 
    z !.!~
}

0

자바 스크립트 (ES6), 192 바이트

v=a=>Math.min(...a=a.map(s=>s.length))==Math.max(...a);
f=(s,t=(u=` `.repeat(w=s.search`
`+1))+`
`+s.replace(/^|$/gm,` `)+`
`+u,v=t.replace(RegExp(`( |@)([^]{${w},${w+2}})?(?!\\1)[ @]`),`@$2@`))=>t!=v?f(s,v):/ /.test(t)?f(s,t.replace(` `,`@`))+1:-1
<textarea id=i rows=10 cols=10></textarea><input type=button value=Count onclick=o.textContent=/^[\s#]+$/.test(i.value)*v(i.value.split`\n`)?f(i.value):`Invalid_Entry`><span id=o>

Failing Castles 에 대한 나의 답변에 근거 함 . 먼저 문자열 주위에 공백을 채워 모양 주위에 영역을 만듭니다. 그런 다음 RegExp는 두 개의 인접한 정사각형을 찾습니다 @. 하나는 공백을 포함하고 다른 하나는 공백을 포함합니다 @. 이 작업을 수행 할 수 없으면@ 새 구멍으로 계산합니다. 마지막으로 주변 지역을 설명하기 위해 하나를 뺍니다.


어떤 종류의 TIO 링크를 제공 할 수 있습니까? 감사!
— HyperNeutrino
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.