Combinaciones Kakuro

12

Combinaciones Kakuro

Debido a que no puedo hacer cálculos aritméticos mentales, a menudo lucho con el rompecabezas de Kakuro , que requiere que la víctima averigüe repetidamente qué números distintos en el rango del 1 al 9 (inclusive) suman otro número en el rango del 1 al 45 cuando sabes cómo muchos numeros hay. Por ejemplo, si desea saber cómo obtener 23 de 3 números, la única respuesta es 6 + 8 + 9. (Esta es la misma idea que Killer Sudoku si está familiarizado con eso).

A veces tendrá otra información, como que el número 1 no puede estar presente, por lo tanto, para lograr 8 en solo 2 números, solo puede usar 2 + 6 y 3 + 5 (no puede usar 4 + 4, porque son no distinto). Alternativamente, puede ser que ya haya encontrado un 3 en la solución, por lo que algo como 19 en 3 números debe ser 3 + 7 + 9.

Su tarea es escribir un programa que enumere todas las posibles soluciones a un problema dado, en un orden estricto, en un diseño estricto.

Entrada

Su solución puede recibir las entradas como una sola cadena ASCII, ya sea a través de stdin, un argumento de línea de comando, un argumento para una función, un valor que queda en la pila o cualquier locura que emplee su lenguaje esotérico favorito. La cadena tiene la forma

number_to_achieve number_of_numbers_required list_of_rejected_numbers list_of_required_numbers

Los primeros 2 argumentos son enteros típicos de base 10 no negativos no cero en los rangos 1 a 45 y 1 a 9 respectivamente (el uso de un punto decimal sería una entrada no válida), las dos listas son solo dígitos unidos sin ninguna delimitación en sin orden particular sin repetición, o '0' si son listas vacías. No puede haber dígitos compartidos entre las listas (excepto para 0). Los delimitadores son espacios individuales.

Salida

Su salida debe comenzar con una línea que contenga el número de posibles soluciones. Su programa debe imprimir soluciones delimitadas por saltos de línea, ordenadas por cada dígito cada vez más significativo, donde cada dígito se coloca en la posición en la que estaría si enumerara los números del 1 al 9. Los ejemplos a continuación, con suerte, lo aclararán.

Si se proporciona una entrada no válida, no me importa lo que haga su programa, aunque prefiero que no ponga a cero mi sector de arranque.

Ejemplos

Para este ejemplo de entrada

19 3 0 0

El resultado esperado sería

5
 2     89
  3   7 9
   4 6  9
   4  78 
    56 8 

Tenga en cuenta los espacios en lugar de cada número "perdido", estos son obligatorios; No me preocupan los espacios que no tienen un número después de ellos (como los 9 que faltan arriba). Puede suponer que lo que sea que esté imprimiendo utilizará una fuente monoespacio. Tenga en cuenta también el orden, por el cual las soluciones con un dígito más pequeño más pequeño se enumeran primero, y luego aquellas con el siguiente dígito más pequeño, etc.

Otro ejemplo, basado en lo anterior

19 3 57 9

El resultado esperado sería

2
 2     89
   4 6  9

Tenga en cuenta que cada resultado contiene un 9, y ningún resultado contiene un 5 o 7.

Si no hay soluciones, por ejemplo

20 2 0 0

Entonces solo debe generar una sola línea con un 0.

0

He hecho que el análisis de la entrada sea parte de la diversión de esta pregunta. Este es el código de golf, que gane la solución más corta.

VisualMelon
fuente
2
+1 esp. para "... Prefiero que no ponga a cero mi sector de arranque".
Michael Easter

Respuestas:

5

GolfScript, 88 caracteres

~[[]]10,:T{{1$+}+%}/\{\0+`-!}+,\{0`+\`&!}+,\{\,=}+,\{\{+}*=}+,.,n@{1T>''*T@-{`/' '*}/n}/

Una implementación sencilla en GolfScript. Toma información de STDIN o stack.

El código se puede probar aquí .

Código con algunos comentarios:

### evaluate the input string
~                     

### build all possible combinations of 0...9
[[]]              # start with set of empty combination
10,:T             #
{                 # for 0..9
  {1$+}+%         #   copy each item of set and append current digit to this copy
}/                # end for

### only keep combination which the digits given as last argument (minus 0)
\{                # start of filter block
  \0+`            #   add zero to combination and make string out of it
  -!              #   subtract from last argument -> check argument contains any
                  #     excess characters
}+,               # end of filter block


### remove any combination which contains either 0 or any digit from 2nd last argument
\{                # start of filter block
  0`+             #   take argument and append 0
  \`              #   stringify combination
  &!              #   check if no characters are common
}+,               # end of filter block

### filter for correct length
\{                # start of filter block
  \,              #   calc length of combination
  =               #   check if equal to second argument
}+,               # end of filter block

### filter for correct sum
\{                # start of filter block
  \{+}*           #   sum all digits of combination
  =               #   compare with first argument
}+,               # end of filter block

### output
.,                # determine size of set
n                 # append newline
@{                # for each combination in set
  1T>''*          #   generate "123456789"
  T@-             #   generate anti-set of current combination  
  {`/' '*}/       #   replace (in the string) each digit within the 
                  #   anti-combination with a space characters
  n               #   append newline
}/                # end for
Howard
fuente
5

JavaScript (E6) 172 180 275 296

Como una función (comprobable) con 1 argumento de cadena y devolviendo la salida solicitada. Para tener un cambio de salida real, regrese con alert (), mismo conteo de bytes, pero tenga cuidado, la fuente de alerta no es monoespacio.

F=i=>{
  [t,d,f,m]=i.split(' ');
  for(l=0,r='',k=512;--k;!z&!h&!o&&(++l,r+=n))
    for(z=n='\n',h=d,o=t,b=i=1;i<=9;b+=b)
      z-=~(b&k?(--h,o-=i,n+=i,f):(n+=' ',m)).search(i++);
  return l+r
}

Prueba en la consola FireFox o FireBug

console.log(['19 3 0 0','19 3 57 9','19 3 57 4','20 2 0 0'].map(x=>'\n'+x+'\n' +F(x)).join('\n'))

Prueba de salida:

19 3 0 0
5
 2     89
  3   7 9
   4 6  9
   4  78 
    56 8 

19 3 57 9
2
 2     89
   4 6  9

19 3 57 4
1
   4 6  9

20 2 0 0
0

Sin golf

F=i=>{
  [target, digits, forbidden, mandatory]=i.split(' ')

  result = '', nsol=0
  for (mask = 0b1000000000; --mask > 0;)
  {
    cdigits = digits
    ctarget = target
    bit = 1
    numbers = ''
    for (digit = 9; digit > 0; bit += bit, digit--)
    {

      if (bit & mask)
      {
        if (forbidden.search(digit)>=0) break;
        cdigits--;
        ctarget -= digit;
        numbers = digit + numbers;
      }
      else
      {
        if (mandatory.search(digit)>=0) break;
        numbers = ' '+numbers;
      }
    }
    if (ctarget==0 && cdigits == 0)
    {
        result += '\n'+numbers
        nsol++
    }
  }
  return nsol + result
}
edc65
fuente
4

Mathematica, 239 bytes

(Admito que comencé a trabajar en esto mientras todavía estaba en el sandbox).

{t,n,a,b}=FromDigits/@StringSplit@i;Riffle[c=Cases[Union/@IntegerPartitions[t,n,Complement[r=Range@9,(d=IntegerDigits)@a]],k_/;(l=Length)@k==n&&(b==0||l[k⋂d@b]>0)];{(s=ToString)@l@c}~Join~((m=#;If[m~MemberQ~#,s@#," "]&/@r)&/@c),"\n"]<>""

Sin golf

{t, n, a, b} = FromDigits /@ StringSplit@i;
Riffle[
  c = Cases[
    Union /@ IntegerPartitions[
      t, n, Complement[r = Range@9, (d = IntegerDigits)@a
       ]
      ],
    k_ /; (l = Length)@k == 
       n && (b == 0 || l[k ⋂ d@b] > 0)
    ];
  {(s = ToString)@l@c}~
   Join~((m = #; If[m~MemberQ~#, s@#, " "] & /@ r) & /@ c),
  "\n"] <> ""

Espera que la cadena de entrada se almacene en i.

Es bastante sencillo. Primero, el análisis de entrada. Luego uso IntegerPartitionspara descubrir cómo puedo dividir el primer número en los números permitidos. Luego filtro todas las particiones que usan duplicados o no contienen los números requeridos. Y luego, para cada solución, creo una lista de 1a 9y convierto los números actuales en su representación de cadena y los demás en espacios. Y luego concateno todo.

Martin Ender
fuente
1

Groovy - 494 caracteres

Respuesta grande y sin inspiración, pero utiliza Google Guava para generar el "conjunto de potencia".

Golfizado:

@Grab(group='com.google.guava', module='guava', version='17.0')
m=(args.join(" ")=~/(\d+) (\d+) (\d+) (\d+)/)[0]
i={it as int}
n=i(m[1])
r=i(m[2])
j=[]
m[3].each{if(i(it))j<<i(it)}
q=[]
m[4].each{if(i(it))q<<i(it)}
d=1..9 as Set<Integer>
t=[]
com.google.common.collect.Sets.powerSet(d).each{x->
if(x.sum()==n&&x.size()==r&&x.disjoint(j)&&x.containsAll(q)) {
s="";for(i in 0..8){if(x.contains(i+1)){s+=(i+1) as String}else{s+=" "}};t<<s}
}
p={println it}
p t.size()
t.sort().reverse().each{p it}

Ejecuciones de muestra:

$ groovy K.groovy 19 3 0 0 
5
 2     89
  3   7 9
   4 6  9
   4  78 
    56 8 
$ groovy K.groovy 19 3 5 0 
4
 2     89
  3   7 9
   4 6  9
   4  78 
$ groovy K.groovy 19 3 5 9
3
 2     89
  3   7 9
   4 6  9
$ groovy K.groovy 20 2 0 0 
0

Sin golf:

@Grab(group='com.google.guava', module='guava', version='17.0')

m=(args.join(" ")=~/(\d+) (\d+) (\d+) (\d+)/)[0]
i={it as int}
n=i(m[1])
r=i(m[2])

j=[]
m[3].each{if(i(it))j<<i(it)}
q=[]
m[4].each{if(i(it))q<<i(it)}

d=1..9 as Set<Integer>
t=[]

com.google.common.collect.Sets.powerSet(d).each{ x ->
    if(x.sum()==n && x.size()==r && x.disjoint(j) && x.containsAll(q)) {
        s=""
        for(i in 0..8) {
            if(x.contains(i+1)){s+=(i+1) as String}else{s+=" "}
        }
        t<<s
    }
}

p={println it}
p t.size()
t.sort().reverse().each{p it}
Michael Easter
fuente