Le gouvernement a une offre limitée de murs

28

introduction

Des golfeurs avertis nous ont préparés pour l'inondation du jugement dernier . Les zones à risque ont été évacuées et la population s'est déplacée vers les hauteurs.

Nous avons sous-estimé le déluge (ou peut-être qu'il y avait un bogue dans le code de @ user12345). Certaines zones d'altitude approchent rapidement du niveau de la mer. Des murs doivent être érigés afin d'assurer la survie des campements désormais densément peuplés. Malheureusement, le gouvernement a un approvisionnement limité en murs.

Problème

Notre scénario apocalyptique est décrit par deux nombres sur une seule ligne, net m. Après cette ligne se trouvent des nlignes avec des mvaleurs par ligne, séparées uniquement par un seul espace. Chaque valeur sera l'un des quatre caractères.

  • xInfranchissable. L'eau ne peut pas couler ici. Les murs ne peuvent pas être érigés ici.
  • -Instable. L'eau peut y circuler ici. Les murs ne peuvent pas être érigés ici.
  • .Stable. L'eau peut y circuler. Des murs peuvent être érigés ici.
  • oCampement. L'eau peut y circuler. Si c'est le cas, tout le monde meurt. Les murs ne peuvent pas être construits ici.

L'eau coulera de tous les bords de la carte, à moins que le bord ne soit infranchissable ou qu'un mur soit construit sur la tuile. Écrivez un programme capable de produire le nombre minimum de murs requis pour protéger un campement.

Exemple d'entrée

 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

Exemple de sortie

3

Hypothèses

  • L'eau s'écoule uniquement orthogonalement
  • Les campements n'existent que sous la forme d'un bloc contigu orthonagonalement par scénario
  • Une solution existera toujours (bien qu'elle puisse nécessiter de grandes quantités de murs)
  • Les campements ne peuvent pas être situés sur un bord, car le scénario n'aurait alors aucune solution
  • 2 n<<16
  • 2 m<<16
  • L'entrée peut être fournie par stdin, lue depuis "city.txt" ou acceptée comme un seul argument

Le code le plus court gagne!

Rainbolt
la source
2
Serait-il acceptable que le programme soit correct, tout en prenant plus de temps que l'univers connu n'a existé pour fournir une solution à certains cas du problème?
Claudiu
@Claudiu Je suis un peu nouveau pour Code Golf. Mon exigence n'a pas pu spécifier de délai, donc il n'en existe pas. La charge incombe à la réponse de prouver qu'une solution est correcte pour tous les cas du problème. Si vous avez une solution qui résout certaines (mais pas toutes) les cas de manière intelligente / cool, je vous encourage toujours à la publier juste pour le plaisir.
Rainbolt
2
Le golf de code ne nécessite généralement pas de restrictions de temps.
Hosch250
Cool! Un autre Q: la saisie doit-elle être comme vous l'avez spécifié ou pouvons-nous la mettre sous une autre forme?
Claudiu
@Claudiu Je ne peux rien accepter en dehors des exigences. Vous pouvez cependant suggérer une modification des exigences à l'aide du bouton Modifier . Étant donné qu'il n'y a pas encore de réponse, j'accepterai probablement la modification tout de suite.
Rainbolt

Réponses:

10

Mathematica, 257 253 caractères

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

L'entrée est lue "city.txt".

Explication:

Mathematica a de nombreuses fonctions pour traiter les graphiques.

Tout d'abord, j'ai lu les données de "city.txt".

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

Ensuite, je construis un graphique en grille avec 'm' * 'n' sommets ( GridGraph@d[[1,{2,1}]]), et j'y ajoute un "sommet à l'infini" qui est connecté à chaque sommet sur les "bords" du graphique. Ce sommet est d'où l'eau coule.

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

Et o, xet sdésignent les positions de "o", "x" et "." respectivement.

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

Ensuite, pour tout sous w- ensemble de s(les sous-ensembles sont triés par longueur), je supprime les sommets dans xet wdepuis g( VertexDelete[g,x⋃w]), et je trouve la longueur du chemin le plus court du "sommet à l'infini" au campement o. Si la longueur est infinie, le camp sera sûr. Ainsi, la longueur du premier west le nombre minimum de murs requis pour protéger un campement.

Catch@Do[If[Min[GraphDistance[VertexDelete[g,x⋃w],∞,#]&/@o]==∞,Throw@Length@w],{w,Subsets@s}]
alephalpha
la source
Agréable! Je pensais que je serais écopé par une approche différente dans une langue différente.
Claudiu
1
Votez mais je le ferais plus fièrement si vous expliquiez votre code pour le reste d'entre nous.
Michael Stern
Quelqu'un peut-il garantir que cette réponse est correcte ou fournir un interpréteur en ligne pour "Mathematica"? Ayant du mal à en trouver un.
Rainbolt
1
@Rusher Je l'ai vérifié, et c'est solide. Il n'y a pas d'interprète en ligne pour MM, mais il existe un format de document CDF téléchargeable que moi-même et quelques autres avons commencé à expérimenter pour partager des solutions. Vous pouvez également obtenir Mathematica gratuitement avec l'ordinateur Raspberry Pi ARM, avec la réserve que vous êtes limité par la puissance de calcul de la boîte. FWIW, nous, les utilisateurs MM, faisons de notre mieux pour rester honnêtes les uns avec les autres et nous travaillons à rendre nos soumissions plus accessibles (un problème également rencontré par Matlab, Maple, les langues MS qui ne fonctionnent pas sur Mono, etc.)
Jonathan Van Mat
4

C, 827 799 522

Golfé:

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

L'entrée est donnée avec la hauteur et avec comme arguments de ligne de commande, puis la grille est lue comme une chaîne unique sur stdin comme ceci: ./a.out 6 7 < inputoù l'entrée est sous cette forme (de gauche à droite, de haut en bas):

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

"Lisible":

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

Nulle part aussi courte que la solution de @Claudiu, mais elle est extrêmement rapide. Au lieu de se remplir par les inondations depuis les bords, il trouve le campement et fonctionne vers l'extérieur à partir des jetons «o».

  • S'il rencontre un terrain instable à côté du campement, il étend le campement dessus.
  • Si un campement sur la grille n'a pas au moins un mur dans chaque direction, il se déplace dans cette direction jusqu'à ce qu'il puisse construire un mur.
  • Une fois chaque nouvelle section de mur placée, il revient pour trouver la section de mur suivante à placer.

Exemples d'emplacements muraux:

x..xxxx                           x..xxxx
x..x--x                           x..xoox
x.xx--x                           x3xxoox
x.ooo-.  <-- results in this -->  xooooo1
x.ooo-.                           xooooo2
xxxxxxx                           xxxxxxx
Comintern
la source
Oh approche intéressante! Donne-t-il toujours la réponse la plus courte? Par exemple, quelle réponse donne-t-elle à cette carte ? Il doit être de 3 (marqué où vont les nouveaux murs @). J'ai essayé d'exécuter votre code moi-même, mais cela ne semble pas fonctionner
Claudiu
Oups, il semble que le golf et l'alcool ne se mélangent pas très bien ... J'ai joué au golf avec un comportement indéfini. Devrait être corrigé maintenant avec les 277 caractères inutiles.
Comintern
2
@Claudiu - Voir mon commentaire ci-dessus, les résultats pour la carte que vous avez publiée sont sur pastebin.com/r9fv7tC5 . Cela devrait toujours donner la réponse la plus courte, mais je ne l'ai testée qu'avec 10 ou 15 cartes qui, selon moi, pourraient présenter des cas d'angle. Je serais curieux de voir si quelqu'un peut identifier les cartes pour lesquelles il échoue.
Comintern
4

Python, 553 525 512 449 414 404 387 368 caractères (+4? Pour l'invocation)

J'ai eu beaucoup trop de plaisir à jouer au golf. Il fait 82 octets de plus si vous essayez de le compresser! Voilà une mesure de compacité et de manque de répétition.

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

Les niveaux d'indentation sont des espaces, des tabulations.

Utilisation :

Lit de 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

Appelez comme suit:

$ python floodfill_golf.py 2>X
3

Il 2>Xs'agit de masquer stderr puisque le programme se termine en levant une exception. Si cela est jugé injuste, n'hésitez pas à ajouter 4 caractères pour l'invocation.

Explication :

Force brute simple. Cfait un remplissage et retourne vrai s'il atteint un campement. Pas de rembourrage supplémentaire car il a fallu trop d'espace pour configurer correctement le rembourrage. D, étant donné un ensemble de murs à remplir, appelle Cde tous les points sur le bord de sorte que cela Cexplique ces murs, et imprime la longueur et les sorties si aucun d'entre eux n'a atteint le campement. La liste des murs est également utilisée pour garder une trace du remblai, donc aucune copie de la planche n'est requise! Trickily, Cajoute également tous les espaces vides qu'il trouve à une liste, de Ssorte que la fonction Dest également utilisée pour construire d'abord la liste des espaces vides. Pour cette raison, j'utilise à la sumplace de any, pour garantir que tous les .s sont collectés lors de la première exécution.

J'invoque Dune fois, puis je copie la liste des espaces vides dans la Zmesure où Scela continuera d'être ajouté à (inefficace, mais moins cher en fonction du nombre de caractères). Ensuite, j'utilise itertools.combinationspour sélectionner chaque combo de spots vides, à partir de 0 spots. J'exécute chaque combo Det il affiche la longueur du premier qui fonctionne, levant une exception pour quitter le programme. Si aucune réponse n'est trouvée, rien n'est imprimé.

Notez qu'actuellement, le programme ne fonctionne pas si aucun mur n'est nécessaire. Ce serait +3 caractères pour s'occuper de ce cas; Je ne sais pas si c'est nécessaire.

Notez également qu'il s'agit d'un O(2^n)algorithme, où nest le nombre de cases vides. Donc, pour une planche 15x15 complètement vide avec un campement au milieu, cela prendra 2^(15*15-1)= 2.6959947e+67itérations pour terminer, ce qui va être très long en effet!

Claudiu
la source
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}

Non golfé:

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
}

Beaucoup plus de golf à venir ...

Renvoie 2E9 si aucune solution.

md_rasler
la source
0

Dyalog APL , 91 octets

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

suppose ⎕IO=0, utilise les fonctionnalités de v16.0 ( @et ), le temps d'exécution est exponentiel en nombre de .-s

est évalué en entrée, doit être une matrice de caractères

'xo.'⍳ remplacer xpar 0, opar 1, .par 2 et tous les autres par 3

s←(4,4,⍨⍉)⍣2 une fonction qui entoure une matrice avec 4s

a← affecter la matrice numérique entourée de 4 à une variable a

b←⍸2= best la liste des paires de coordonnées où les 2 (c'est-à-dire les .-s) sont

(,⍳2⊣¨b)/¨⊂b générer toutes les combinaisons d'éléments de b

c[⍋≢¨c←...] les trier par taille

{... :⍬⋄≢⍵}¨ pour chaque combinaison, vérifiez quelque chose et renvoyez sa longueur ou une liste vide

⊃∊ le premier résultat non vide

d←0@⍵⊢a dest aavec certains éléments remplacés par 0

4= créer une matrice booléenne - où sont les 4? c'est-à-dire la frontière que nous avons ajoutée

{...}⍣≡ continuez d'appliquer la fonction {}jusqu'à ce que le résultat se stabilise

3∨/3∨⌿⍵ "booléen ou" chaque élément avec ses voisins

s le résultat sera plus petit, alors recréons la bordure

(×d)∧ appliquer les éléments non nuls de d(les non-murs) comme un masque booléen

a[⍸× ...] qu'est-ce qui acorrespond aux 1 de notre matrice booléenne?

1∊ y a-t-il des 1, c'est o-à- dire des campements?

ngn
la source