Die Regierung verfügt über ein begrenztes Angebot an Mauern

28

Einführung

Erfahrene Code-Golfer haben uns auf die Flut des Jüngsten Gerichts vorbereitet . Risikogebiete wurden evakuiert und die Bevölkerung in die Höhe getrieben.

Wir haben die Flut unterschätzt (oder es gab einen Fehler im Code von @ user12345). Einige hochgelegene Gebiete nähern sich rasch dem Meeresspiegel. Um das Überleben der nun dicht besiedelten Lager zu sichern, müssen Mauern errichtet werden. Leider verfügt die Regierung nur über ein begrenztes Angebot an Mauern.

Problem

Unser Schreckensszenario wird durch zwei Zahlen in einer Zeile beschrieben, nund m. Auf diese Zeile folgen nZeilen mit mWerten pro Zeile, die nur durch ein Leerzeichen voneinander getrennt sind. Jeder Wert besteht aus vier Zeichen.

  • xUnpassierbar. Wasser kann hier nicht fließen. Wände können hier nicht errichtet werden.
  • -Instabil. Hierdurch kann Wasser fließen. Wände können hier nicht errichtet werden.
  • .Stabil. Hier kann Wasser durchströmen. Hier können Wände errichtet werden.
  • oLager. Hier kann Wasser durchströmen. Wenn doch, stirbt jeder. Wände können hier nicht gebaut werden.

Wasser fließt von allen Rändern der Karte, es sei denn, die Kante ist unpassierbar oder die Kachel ist mit einer Wand versehen. Schreiben Sie ein Programm, das die Mindestanzahl von Wänden ausgibt, die zum Schutz eines Lagers erforderlich sind.

Beispiel Eingabe

 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

Beispielausgabe

3

Annahmen

  • Wasser fließt nur orthogonal
  • Lager existieren nur als ein orthonal zusammenhängender Block pro Szenario
  • Es wird immer eine Lösung geben (obwohl dafür möglicherweise viele Wände erforderlich sind)
  • Lager können nicht an einer Kante lokalisiert werden, da das Szenario dann keine Lösung hätte
  • 2 n<<16
  • 2 m<<16
  • Die Eingabe kann von stdin bereitgestellt, aus "city.txt" gelesen oder als einzelnes Argument akzeptiert werden

Kürzester Code gewinnt!

Regenblitz
quelle
2
Wäre es akzeptabel, dass das Programm korrekt ist, es aber länger dauert als das bekannte Universum, um eine Lösung für bestimmte Fälle des Problems zu finden?
Claudiu
@Claudiu Ich bin etwas neu in Code Golf. Meine Anforderung hat kein Zeitlimit angegeben, daher ist eines nicht vorhanden. Die Last liegt bei der Antwort, um zu beweisen, dass eine Lösung für alle Instanzen des Problems korrekt ist. Wenn Sie eine Lösung haben, die einige (aber nicht alle) Fälle auf clevere / coole Weise löst, empfehle ich Ihnen dennoch, sie nur zum Spaß zu veröffentlichen.
Rainbolt
2
Code Golf erfordert normalerweise keine zeitlichen Einschränkungen.
Hosch250
Cool! Eine andere Frage: Muss die Eingabe wie von Ihnen angegeben erfolgen, oder können wir sie in eine andere Form bringen?
Claudiu
@Claudiu Ich kann nichts außerhalb der Anforderungen akzeptieren. Sie können den Anforderungen jedoch über die Schaltfläche Bearbeiten eine Bearbeitung vorschlagen . Da es noch keine Antworten gibt, werde ich die Bearbeitung wahrscheinlich sofort akzeptieren.
Rainbolt

Antworten:

10

Mathematica, 257 253 Zeichen

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}]

Die Eingabe wird von gelesen "city.txt".

Erläuterung:

Mathematica hat viele Funktionen, um mit Graphen umzugehen.

Zuerst lese ich die Daten aus "city.txt".

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

Dann konstruiere ich ein Gitterdiagramm mit 'm' * 'n' Eckpunkten ( GridGraph@d[[1,{2,1}]]) und füge einen "Eckpunkt im Unendlichen" hinzu, der mit jedem Eckpunkt an den "Kanten" des Diagramms verbunden ist. Von diesem Scheitelpunkt fließt das Wasser ab.

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

Und o, xund sbezeichnen die Positionen von "o", "x" und "." beziehungsweise.

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

Dann lösche ich für jede Untergruppe wvon s(die Untergruppen sind nach Länge sortiert) die Scheitelpunkte in xund waus g( VertexDelete[g,x⋃w]) und finde die Länge des kürzesten Pfades vom "Scheitelpunkt im Unendlichen" zum Lager o. Wenn die Länge unendlich ist, ist das Lager sicher. Die Länge der ersten wist also die minimale Anzahl von Wänden, die zum Schutz eines Lagers erforderlich sind.

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]
Alephalpha
quelle
Nett! Ich dachte, ich würde von einem anderen Ansatz in einer anderen Sprache profitieren.
Claudiu
1
Ich würde mich aber eher dafür aussprechen, wenn Sie Ihren Code für den Rest von uns erklären würden.
Michael Stern
Kann jemand für die Richtigkeit dieser Antwort bürgen oder einen Online-Dolmetscher für "Mathematica" bereitstellen? Ich habe Probleme, einen zu finden.
Rainbolt
1
@ Rusher Ich habe es überprüft, und es ist solide. Es gibt keinen Online-Interpreter für MM, aber es gibt ein herunterladbares CDF-Dokumentformat, mit dem ich und einige andere experimentiert haben, um Lösungen auszutauschen. Sie können Mathematica auch kostenlos mit dem Raspberry Pi ARM-Computer erhalten, mit der Einschränkung, dass Sie durch die Rechenleistung der Box begrenzt sind. FWIW, wir MM-Benutzer tun unser Bestes, um einander ehrlich zu halten, und wir arbeiten daran, unsere Beiträge zugänglicher zu machen (ein Problem, mit dem auch Matlab, Maple, MS-Sprachen konfrontiert sind, die in Mono nicht funktionieren usw.)
Jonathan Van Matre
4

C 827 799 522

Golf gespielt:

#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);}

Die Eingabe erfolgt mit der Höhe und mit als Befehlszeilenargumenten, und dann wird das Raster wie folgt als einzelne Zeichenfolge auf stdin gelesen: ./a.out 6 7 < inputwobei die Eingabe in dieser Form erfolgt (von links nach rechts, von oben nach unten):

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

"Lesbar":

#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");
    }   
}

Nicht annähernd so kurz wie die Lösung von @Claudiu, aber sie läuft rasend schnell. Anstatt sich von den Rändern aus zu füllen, findet es das Lager und wirkt von den O-Marken nach außen.

  • Wenn es auf instabilen Boden neben dem Lager stößt, erweitert es das Lager darauf.
  • Wenn ein Lager auf dem Gitter nicht mindestens eine Wand in jede Richtung hat, bewegt es sich in diese Richtung, bis es eine Wand bauen kann.
  • Nachdem jeder neue Wandabschnitt platziert wurde, sucht er erneut den nächsten zu platzierenden Wandabschnitt.

Beispielwandplatzierungen:

x..xxxx                           x..xxxx
x..x--x                           x..xoox
x.xx--x                           x3xxoox
x.ooo-.  <-- results in this -->  xooooo1
x.ooo-.                           xooooo2
xxxxxxx                           xxxxxxx
Komintern
quelle
Oh interessanter Ansatz! Gibt es immer die kürzeste Antwort? zB welche Antwort gibt es für diese Karte ? Es sollte 3 sein (markiert, wo neue Wände mit gehen @). Ich habe versucht, Ihren Code selbst auszuführen, aber es schien nicht zu funktionieren
Claudiu
Hoppla, scheint, dass Golf und Alkohol nicht sehr gut zusammenpassen ... Ich habe in einem undefinierten Verhalten Golf gespielt. Sollte jetzt zusammen mit den 277 unnötigen Zeichen behoben werden .
Comintern
2
@Claudiu - Siehe meinen Kommentar oben, Ergebnisse für die von Ihnen gepostete Karte finden Sie unter pastebin.com/r9fv7tC5 . Dies sollte immer die kürzeste Antwort geben, aber ich habe es nur mit 10 oder 15 Karten getestet, von denen ich dachte, dass sie Eckfälle darstellen könnten. Ich wäre gespannt, ob jemand Karten identifizieren kann, bei denen dies fehlschlägt.
Komintern
4

Python, 553 525 512 449 414 404 387 368 Zeichen (+4? Für den Aufruf)

Ich hatte viel zu viel Spaß beim Golfen. Es ist 82 Bytes größer, wenn Sie versuchen, es zu komprimieren! Das ist ein Maß für Kompaktheit und mangelnde Wiederholung.

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))

Einrückungsstufen sind Leerzeichen, Tabulator.

Verwendung :

Liest aus 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

Rufen Sie wie folgt auf:

$ python floodfill_golf.py 2>X
3

Das 2>Xsoll stderr verstecken, da das Programm durch Auslösen einer Ausnahme beendet wird. Wenn dies als unfair angesehen wird, können Sie 4 Zeichen für den Aufruf hinzufügen.

Erläuterung :

Einfache rohe Gewalt. Cführt eine Überflutung durch und gibt true zurück, wenn es auf ein Lager trifft. Keine zusätzliche Polsterung, da die richtige Polsterung zu viel Platz in Anspruch nahm. DRuft Cvon jedem Punkt an der Kante aus, der Cdiese Wände berücksichtigt, und druckt Länge und Ausgang, wenn keine von ihnen das Lager erreicht. Die Liste der Wände wird auch verwendet, um die Überflutung zu verfolgen, so dass kein Kopieren der Tafel erforderlich ist! Trickily, Cauch alle leeren Stellen hängt sie in eine Liste findet S, so dass die Funktion Dwird auch zum ersten Konstrukt die Liste der leeren Stellen eingesetzt. Aus diesem Grund benutze ich sumstattany , um all das zu gewährleisten. s beim ersten Durchlauf gesammelt werden.

Ich rufe Deinmal, dann die Liste der freien Stellen in kopieren , Zda Szu werden halten angehängt (ineffizient, aber billiger auf Zeichenzählung). Dann benutze ichitertools.combinations , um jede Kombination von leeren Stellen auszuwählen, von 0 Stellen bis. Ich führe jede Kombination durch Dund sie gibt die Länge der ersten funktionierenden aus und löst eine Ausnahme aus, um das Programm zu beenden. Wenn keine Antwort gefunden wird, wird nichts gedruckt.

Beachten Sie, dass das Programm derzeit nicht funktioniert, wenn keine Wände benötigt werden. Es wären +3 Zeichen, um sich um diesen Fall zu kümmern. nicht sicher, ob es notwendig ist.

Beachten Sie auch, dass dies ein O(2^n)Algorithmus ist, bei dem ndie Anzahl der leeren Stellen angegeben ist. Also, für ein 15x15 komplett leeres Brett mit einem Lager in der Mitte, das wird dauern 2^(15*15-1)= 2.6959947e+67Iterationen zu vervollständigen, die in der Tat eine sehr lange Zeit sein werden!

Claudiu
quelle
1

Groovy: 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}

Ungolfed:

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
}

Viel mehr Golfen kommt noch ...

Gibt 2E9 zurück, wenn keine Lösung vorliegt.

md_rasler
quelle
0

Dyalog APL , 91 Bytes

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

geht davon aus ⎕IO=0, dass Funktionen ab v16.0 ( @und ) verwendet werden und die Laufzeit in der Anzahl .-s exponentiell ist

Eingaben ausgewertet wird, muss eine Matrix von Zeichen sein

'xo.'⍳ Ersetze xmit 0, omit 1, .mit 2 und alle anderen mit 3

s←(4,4,⍨⍉)⍣2 eine Funktion, die eine Matrix mit 4s umgibt

a← Weisen Sie einer Variablen die mit 4s umgebene numerische Matrix zu a

b←⍸2= bist die Liste der Koordinatenpaare, in denen sich die 2en (dh die .-s) befinden

(,⍳2⊣¨b)/¨⊂b generiere alle Kombinationen von Elementen von b

c[⍋≢¨c←...] sortiere sie nach Größe

{... :⍬⋄≢⍵}¨ Überprüfen Sie für jede Kombination etwas und geben Sie entweder dessen Länge oder eine leere Liste zurück

⊃∊ das erste nicht leere Ergebnis

d←0@⍵⊢a dwird abei einigen Elementen durch 0 ersetzt

4= Boolesche Matrix erstellen - wo sind die 4er? dh die Grenze, die wir hinzugefügt haben

{...}⍣≡ Wenden Sie die Funktion so lange an, {}bis sich das Ergebnis stabilisiert hat

3∨/3∨⌿⍵ "boolean" oder "jedes Element mit seinen Nachbarn"

s Das Ergebnis wird kleiner, also erstellen wir den Rahmen neu

(×d)∧ Wenden Sie die Nicht-Null-Elemente von d(die Nicht-Wände) als Boolesche Maske an

a[⍸× ...] Was aentspricht der 1 in unserer Booleschen Matrix?

1∊ Gibt es Einsen, dh oLager?

ngn
quelle