정부는 벽의 공급이 제한되어있다


28

소개

지식 이 풍부한 코드 골퍼 들이 최후의 홍수에 대비해 우리를 준비 시켰습니다 . 위험에 처한 지역은 대피했고, 인구는 고지대로 이동했습니다.

우리는 홍수를 과소 평가했거나 아마도 @ user12345의 코드에 버그가 있었을 것입니다. 일부 고지대는 해수면에 빠르게 접근하고 있습니다. 현재 인구 밀도가 높은 야영지의 생존을 보장하기 위해 벽을 세워야합니다. 안타깝게도 정부는 벽 공급이 제한되어 있습니다.

문제

우리의 종말 시나리오는 한 줄에 두 숫자에 의해 설명되어 nm. 그 라인 다음에는 라인 당 값 이있는 n라인이 있으며 m, 단일 공백으로 만 분리됩니다. 각 값은 4 자 중 하나입니다.

  • x지나갈 수 없는. 물이 흐르지 않습니다. 여기에는 벽을 세울 수 없습니다.
  • -불안정한. 여기를 통해 물이 흐를 수 있습니다. 여기에는 벽을 세울 수 없습니다.
  • .안정된. 물이 여기를 통해 흐를 수 있습니다. 여기에 벽을 세울 수 있습니다.
  • o야영지. 물이 여기를 통해 흐를 수 있습니다. 그렇다면 모두가 죽습니다. 여기에는 벽을 지을 수 없습니다.

가장자리가 통과 할 수 없거나 타일이 벽에 구성되어 있지 않으면지도의 모든 가장자리에서 물이 흐릅니다. 야영을 보호하는 데 필요한 최소 수의 벽을 출력 할 수있는 프로그램을 작성하십시오.

입력 예

 6 7
 x . . x x x x
 x . . x - - x
 x . x x - - x
 x . o o o - .
 x . o o o - .
 x x x x x x x

출력 예

3

가정

  • 물은 직교로만 흐릅니다.
  • 야영은 시나리오 당 하나의 직교 연속 블록으로 만 존재합니다.
  • 해결책은 항상 존재할 것입니다 (많은 양의 벽이 필요할 수는 있지만)
  • 시나리오에는 해결책이 없으므로 야영지를 가장자리에 배치 할 수 없습니다.
  • 2 << n16
  • 2 << m16
  • 입력은 stdin에서 제공되거나 "city.txt"에서 읽거나 단일 인수로 허용 될 수 있습니다.

최단 코드 승리!


2
프로그램이 정확하지만 문제의 특정 사례에 대한 해결책을 제공하기 위해 알려진 우주가 존재했던 것보다 시간이 오래 걸리는가?
Claudiu

@Claudiu 저는 Code Golf를 처음 사용합니다. 요구 사항에 시간 제한을 지정하지 못하여 시간 제한이 없습니다. 해결책이 문제의 모든 인스턴스에 대해 올바른지 증명하기위한 부담은 대답에 있습니다. 영리하고 멋진 방법으로 일부 (전부는 아님) 인스턴스를 해결하는 솔루션이 있다면 여전히 재미있게 게시하는 것이 좋습니다.
Rainbolt

2
코드 골프는 일반적으로 시간 제한이 필요하지 않습니다.
Hosch250

시원한! 또 다른 Q : 입력 한 내용은 지정한대로 입력해야합니까, 아니면 다른 형식으로 입력 할 수 있습니까?
Claudiu

@Claudiu 요구 사항 외에는 아무것도 받아 들일 수 없습니다. 그러나 편집 버튼을 사용하여 요구 사항에 대한 편집을 제안 할 수 있습니다 . 아직 답변이 없으므로 수정 사항을 즉시 수락 할 것입니다.
Rainbolt

답변:


10

매스 매 티카, 257253

d="city.txt"~Import~"Table";g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]

에서 입력을 읽습니다 "city.txt".

설명:

Mathematica에는 그래프를 다루는 많은 기능이 있습니다.

먼저에서 데이터를 읽습니다 "city.txt".

d="city.txt"~Import~"Table";

그런 다음 'm'* 'n'꼭짓점 ( )을 사용 하여 그리드 그래프 를 구성하고 그래프GridGraph@d[[1,{2,1}]] 의 "가장자리"에있는 모든 꼭짓점에 연결된 "무한대 정점"을 추가합니다. 이 정점은 물이 흐르는 곳입니다.

g=EdgeAdd[#,∞<->Tr@#&/@Position[VertexDegree@#,2|3]]&@GridGraph@d[[1,{2,1}]];

그리고 o, x그리고 s, "X"와 "O"의 위치를 나타내는 "." 각기.

{o,x,s}=Tr/@Position[Join@@d[[2;;]],#]&/@{"o","x","."};

그리고 어떤 부분 집합 ws(하위 집합이 길이으로 분류되어 있습니다), 나는에 정점을 삭제 x하고 w에서 g( VertexDelete[g,x⋃w]), 및 야영지에 "무한 정점"에서 최단 경로의 길이를 찾을 수 있습니다 o. 길이가 무한대이면 야영이 안전합니다. 따라서 첫 번째 길이 w는 야영지를 보호하는 데 필요한 최소 벽 수입니다.

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]

좋은! 나는 다른 언어로 된 다른 접근법에 휩싸 일 것이라고 생각했다.
Claudiu

1
반대 의견이지만 다른 사람들을 위해 코드를 설명하면 더 자랑스럽게 생각합니다.
Michael Stern

이 답변이 정확하다고 보증하거나 "Mathematica"에 대한 온라인 통역사를 제공 할 수 있습니까? 하나를 찾는 데 문제가 있습니다.
Rainbolt

1
@Rusher 나는 그것을 확인했고, 견고합니다. MM에 대한 온라인 통역사는 없지만 다운로드 가능한 CDF 문서 형식은 나와 다른 사람들이 솔루션을 공유하기 위해 실험하기 시작했습니다. Raspberry Pi ARM 컴퓨터를 통해 Mathematica를 무료로받을 수 있으며, 상자의 컴퓨팅 성능에 제한이 있다는 경고가 있습니다. FWIW, MM 사용자는 서로 정직하게 유지하기 위해 최선을 다하며 제출물에보다 쉽게 ​​접근 할 수 있도록 노력하고 있습니다 (Matlab, Maple, Mono에서는 작동하지 않는 MS 언어 등의 문제도 있습니다)
Jonathan Van Matre

4

C, 827 799 522

골프 :

#define N for(
#define F(W,X,Y,Z) N i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}
p,m,z,w,h,o,i,u,l,x,y;char c[16][16];Q(){N u=0;u<h;u++)N l=0;l<w;l++)if(c[u][l]=='o'){x=u;y=l;S(x,>,m,--,i,y)S(y,>,m,--,x,i)S(y,<,w,++,x,i)S(x,<,h,++,i,y)}}main(int a, char **v){h=atoi(v[1]);w=atoi(v[2]);N m=-1;o<h;o++)N i=0;i<w;i++)scanf("%c",&c[o][i]);Q();printf("%d",z);}

입력은 높이와 명령 행 인수로 제공되며 그리드는 stdin에서 다음과 같이 단일 문자열로 읽습니다 ./a.out 6 7 < input.

x..xxxxx..x--xx.xx--xx.ooo-.x.ooo-.xxxxxxx

"판독 가능":

#define F(W,X,Y,Z) for(i= W;i X Y;i Z)
#define C(A,B,C) if(c[A][B]==C)
#define S(W,X,Y,Z,A,B) p=1;F(W,X,Y,Z)C(A,B,120)p=0;if(p){F(W,X,Y,Z){C(A,B,46){c[A][B]='x';z++;Q();break;}}}else{F(W,X,Y,Z){C(A,B,120)break;else c[A][B]='o';}}

/*Example of an expanded "S" macro:
p=1;
for(i=x;i>m;i--) if(c[i][y]==120) p=0;
if(p)
{
    for(i=x;i>m;i--)
    {
        if(c[i][y]==46)
        {
            c[i][y]='x';
            z++;
            Q();
            break;
        }
    }
}
else
{
    for(i= x;i > m;i --)
    {
        if(c[i][y]==120) break;
        else c[i][y]='o';
    }
}
*/

p,m,z,w,h,o,i,u,l,x,y;
char c[16][16];
Q(){
    for(u=0;u<h;u++)
        for(l=0;l<w;l++)
            if(c[u][l]=='o')
            {
        x=u;y=l;
        S(x,>,m,--,i,y)
        S(y,>,m,--,x,i)
        S(y,<,w,++,x,i)
        S(x,<,h,++,i,y)
            }
}

main(int a, char **v)
{
    h=atoi(v[1]);
    w=atoi(v[2]);
    for(m=-1;o<h;o++)
        for(i=0;i<w;i++)
            scanf("%c",&c[o][i]);
    P();
    Q();
    printf("%d\n",z);
    P();
}

//Omitted in golfed version, prints the map.
P()
{
    for(o=0;o<h;o++)
    {
        for (i=0;i<w;i++) printf("%c",c[o][i]);
        printf("\n");
    }   
}

@Claudiu의 솔루션만큼 짧지는 않지만 놀랍도록 빠르게 실행됩니다. 가장자리에서 홍수를 채우는 대신 야영지를 찾아 'o'토큰에서 바깥쪽으로 작동합니다.

  • 야영지 옆에 불안정한 땅이 있으면 야영지를 확대합니다.
  • 그리드의 야영지에 각 방향으로 벽이 하나 이상없는 경우 벽을 만들 수있을 때까지 해당 방향으로 이동합니다.
  • 각각의 새 벽 섹션을 배치 한 후 배치 할 다음 벽 섹션을 찾기 위해 반복됩니다.

샘플 벽 배치 :

x..xxxx                           x..xxxx
x..x--x                           x..xoox
x.xx--x                           x3xxoox
x.ooo-.  <-- results in this -->  xooooo1
x.ooo-.                           xooooo2
xxxxxxx                           xxxxxxx

오 재미있는 접근법! 항상 가장 짧은 답변을 제공합니까? 예를 들어이 지도에 어떤 대답을 합니까? 3이어야합니다 (새 벽이있는 곳에 표시 @). 직접 코드를 실행 해 보았지만 작동 하지 않는 것 같습니다
Claudiu

죄송합니다. 골프와 알코올이 잘 섞이지 않는 것 같습니다 ... 정의되지 않은 동작으로 골프를 쳤습니다. 277 개의 불필요한 문자 와 함께 수정해야합니다 .
Comintern

2
@Claudiu-위의 내 의견보기, 게시 한지도에 대한 결과는 pastebin.com/r9fv7tC5에 있습니다. 이것은 항상 가장 짧은 대답을 제공 해야 하지만 코너 사례를 제시 할 수 있다고 생각한 10 또는 15 개의지도로 테스트했습니다. 누군가 실패한지도를 식별 할 수 있는지 궁금합니다.
Comintern

4

파이썬 553 525 512 449 414 404 387 368 문자 (호출 용 +4?)

나는 이것을 너무 재미있게 골프를 쳤다. 압축하려고하면 82 바이트가 더 커집니다! 이제는 압축성과 반복성 부족의 척도입니다.

R=range;import itertools as I
f=map(str.split,open('city.txt'))[1:]
S=[]
def D(q):
 q=set(q)
 def C(*a):
    r,c=a
    try:p=(f[r][c],'x')[a in q]
    except:p='x'
    q.add(a)
    if'.'==p:S[:0]=[a]
    return p<'/'and C(r+1,c)|C(r-1,c)|C(r,c+1)|C(r,c-1)or'o'==p
 if sum(C(j,0)|C(j,-1)|C(0,j)|C(-1,j)for j in R(16))<1:print n;B
D(S);Z=S[:]
for n in R(len(Z)):map(D,I.combinations(Z,n))

들여 쓰기 수준은 공백, 탭입니다.

사용법 :

에서 읽는다 city.txt:

6 7
x . . x x x x
x . . x - - x
x . x x - - x
x . o o o - .
x . o o o - .
x x x x x x x

다음과 같이 호출하십시오.

$ python floodfill_golf.py 2>X
3

2>X예외를 발생하여 프로그램이 종료 이후 표준 에러를 숨기는 것입니다. 이것이 불공평 한 것으로 간주되면 호출에 4자를 추가하십시오.

설명 :

단순한 무차별 대입. C플러드 채우기를 수행하고 야영지에 도달하면 true를 반환합니다. 패딩을 올바르게 설정하기에는 공간이 너무 많이 소비되어 추가 패딩이 없습니다. D채울 벽이 주어진 C경우 모서리의 모든 지점에서 C벽을 설명하고 길이를 인쇄하고 야영지에 도달하지 않으면 길이를 인쇄합니다. 벽의 목록은 홍수 채우기를 추적하는 데에도 사용되므로 보드를 복사 할 필요가 없습니다! Trickily, C또한 목록에 발견 빈 지점을 추가, S그래서 기능이 D있다 또한 첫번째 구조에 빈 지점의 목록을 사용했다. 이러한 이유로 나는 sum대신에을 사용 any하여 모든 .s가 첫 번째 통과시 수집 되도록합니다 .

나는 호출 D다음에 빈 지점의 목록 복사 번 Z부터 S(글자 수에 비효율적하지만 저렴)에 추가되고 유지됩니다. 그런 다음 itertools.combinations빈 자리의 각 콤보를 0 자리부터 선택합니다. 각 콤보를 실행 D하고 작동하는 첫 번째 길이를 인쇄하여 프로그램 종료 예외를 발생시킵니다. 응답이 없으면 아무것도 인쇄되지 않습니다.

현재 벽이 필요하지 않으면 프로그램이 작동하지 않습니다. 이 경우는 +3 자입니다. 필요한지 확실하지 않습니다.

또한 이것은 빈 자리의 수인 O(2^n)알고리즘 n입니다. 따라서 중간에 하나의 야영지가있는 15x15 완전히 비어있는 보드의 경우 2^(15*15-1)= 2.6959947e+67반복이 완료됩니다. 실제로 오랜 시간 이 걸릴 것입니다!


1

그루비 : 841 805 754

i=new File("city.txt").getText()
x=i[2] as int
y=i[0] as int
m=i[4..i.length()-1].replaceAll('\n','').toList()
print r(m,0)
def r(m,n){if(f(m))return n;c=2e9;g(m).each{p=r(it,n+1);if(p<c)c=p;};return c;}
def f(m){u=[];u.addAll(m);for(i in 0..(x*y)){for(l in 0..m.size()-1){n(l,u);s(l,u);e(l,u);w(l,u);}};m.count('o')==u.count('o')}
def n(i,m){q=i-x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def s(i,m){q=i+x;if((((q>=0)&(m[q]=='!'))|(q<0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def e(i,m){q=i+1;if((((q%x!=0)&(m[q]=='!'))|(q%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def w(i,m){q=i-1;if((((i%x!=0)&(m[q]=='!'))|(i%x==0))&m[i]!='x'&m[i]!='W'){m[i]='!'}}
def g(m){v=[];m.eachWithIndex{t,i->if(t=='.'){n=[];n.addAll(m);n[i]='W';v<<n}};return v}

언 골프 드 :

def i = new File("city.txt").getText()
x=i[2].toInteger()
y=i[0].toInteger()
def m=i[4..i.length()-1].replaceAll('\n','').toList()
println r(m, 0)

def r(m, n){
    if(f(m)) return n
    def c = Integer.MAX_VALUE

    getAllMoves(m).each{ it -> 
        def r = r(it, n+1)
        if(r < c) c = r
    }
    return c;
}

def f(m){
    def t = []
    t.addAll(m)
    for(i in 0..(x*y)){
        for(l in 0..m.size()-1){
            n(l,t);s(l,t);e(l,t);w(l,t);
        }
    }
    m.count('o')==t.count('o')
}

def n(i,m){
    def t = i-x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def s(i,m){
    def t = i+x;
    if( ( ( (t >= 0) && (m[t]=='!') ) || (t < 0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def e(i,m){
    def t = i+1;
    if( ( ( (t%x!=0) && (m[t]=='!') ) || (t%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    } 
}

def w(i,m){
    def t = i-1;
    if( ( ( (i%x!=0) && (m[t]=='!') ) || (i%x==0)) && m[i]!='x' && m[i]!='W'){
        m[i]='!'
    }
}

def getAllMoves(m){
    def moves = []
    m.eachWithIndex { t, i ->
        if(t=='.'){
            def newList = []
            newList.addAll(m)
            newList[i]='W'
            moves << newList
        }
    }
    return moves
}

앞으로 더 많은 골프 ...

해가 없으면 2E9를 반환합니다.


0

Dyalog APL , 91 바이트

⊃∊{1∊a[⍸×{(×d)∧s 3∨/3∨⌿⍵}⍣≡4=d←0@⍵⊢a]:⍬⋄≢⍵}¨c[⍋≢¨c←(,⍳2⊣¨b)/¨⊂b←⍸2=a←(s←(4,4,⍨⍉)⍣2)'xo.'⍳⎕]

가정 ⎕IO=0(v16.0 용도에서 기능 @하고 , 실행 시간은 수의 지수 함수이다) .-s

입력으로 평가되며 문자 행렬이어야합니다.

'xo.'⍳x0으로, o1로, .2로, 다른 모든 것은 3으로 대체하십시오.

s←(4,4,⍨⍉)⍣2 4로 매트릭스를 둘러싸는 함수

a← 4로 둘러싸인 숫자 행렬을 변수에 할당 a

b←⍸2= b2 (즉, .-s)가 있는 좌표 쌍의 목록입니다.

(,⍳2⊣¨b)/¨⊂b 요소의 모든 조합을 생성 b

c[⍋≢¨c←...] 크기별로 정렬

{... :⍬⋄≢⍵}¨ 각 조합에 대해 무언가를 확인하고 길이 또는 빈 목록을 반환하십시오.

⊃∊ 비어 있지 않은 첫 결과

d←0@⍵⊢a da0으로 대체 일부 요소

4= 부울 행렬 만들기-4는 어디에 있습니까? 즉 우리가 추가 한 테두리

{...}⍣≡{}결과가 안정 될 때까지 계속 함수를 적용하십시오

3∨/3∨⌿⍵ "부울 또는"각 요소와 이웃 요소

s 결과는 더 작아 질 것이므로 테두리를 다시 만들어 봅시다.

(×d)∧d벽이 아닌 요소의 0이 아닌 요소를 부울 마스크로 적용

a[⍸× ...]a부울 행렬의 1 에 해당하는 것은 무엇 입니까?

1∊ 어떤 1 초, 즉있다 o, 야영은?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.