몇 개의 구멍?


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.