Cuente cadenas binarias equilibradas que coincidan con cualquiera de un conjunto de máscaras

10

Una cadena binaria es una cadena que contiene solo caracteres extraídos de 01 . Una cadena binaria balanceada es una cadena binaria que contiene exactamente tantos 0 s como 1 s.

Se le da un número entero positivo n y un número arbitrario de máscaras, cada una de las cuales tiene 2n caracteres de longitud y contiene solo caracteres extraídos de 012 . Una cadena binaria y una máscara coinciden si tiene la misma longitud y concuerda con el personaje en cada posición donde la máscara no tiene un 2 . Por ejemplo, la máscara 011022 coincide con las cadenas binarias 011000 , 011001 , 011010 , 011011 .

Dado n y las máscaras como entrada (separadas por nuevas líneas), debe generar el número de cadenas binarias equilibradas distintas que coinciden con una o más de las máscaras.

Ejemplos

Entrada

3
111222
000112
122020
122210
102120

Razonamiento

  • La única cadena binaria equilibrada que coincide con 111222 es 111000 .
  • La única cadena binaria equilibrada que coincide con 000112 es 000111 .
  • Las cadenas binarias balanceadas que coinciden con 122020 son 111000 (ya contadas), 110010 y 101010 .
  • Las cadenas binarias balanceadas que coinciden con 122210 son 110010 (ya contadas), 101010 (ya contadas) y 100110 .
  • Las cadenas binarias balanceadas que coinciden con 102120 son 101100 y 100110 (ya contadas).

Entonces la salida debería ser

6

Entrada

10
22222222222222222222

Razonamiento

  • Hay 20 elegir 10 cadenas binarias balanceadas de longitud 20.

Salida

184756

Ganador

El ganador será el que calcule la entrada de la competencia más rápido, por supuesto, tratándola de la misma manera que lo haría con cualquier otra entrada. (Utilizo un código determinado para tener un ganador claro y evitar casos en los que diferentes entradas darían ganadores diferentes. Si piensas en una mejor manera de encontrar el código más rápido, dímelo).

Aporte de competencia

http://pastebin.com/2Dg7gbfV

Masclins
fuente
2
Además, personalmente prefiero gist.github.com sobre pastebin, tanto por razones estéticas como futuras.
orlp
3
@AlbertMasclans Creo que debería reservarse el derecho de cambiar la entrada. De lo contrario, alguien puede codificar la salida.
mbomb007
1
Sería útil si pudiera publicar un pequeño ejemplo en la pregunta, con el resultado esperado y una explicación. Puede que sea lento, pero no entiendo bien la definición. Entonces, para el ejemplo, dado que n = 30, ¿estamos buscando secuencias de 30 0s o 30 1s (siendo 2 un comodín) en cualquier fila? ¿Se pueden superponer esas secuencias? Por ejemplo, si encuentro una secuencia de 32 1s, ¿eso cuenta como 3 secuencias o como una secuencia única? ¿Qué sucede si encuentro una secuencia de 60 1s (fila completa)? ¿Es esa 1 secuencia, 2 secuencias o 31 secuencias?
Reto Koradi
3
Entonces, está preguntando por el número de matrices únicas en esta matriz que tienen números iguales de 1s y 0s, ¿verdad?
ASCIIThenANSI
1
¿Podemos tener más datos de prueba por favor?
alexander-brett

Respuestas:

2

C

Si no está en Linux o tiene problemas para compilar, probablemente debería eliminar el código de sincronización ( clock_gettime).

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

long int binomial(int n, int m) {
  if(m > n/2) {
    m = n - m;
  }
  int i;
  long int result = 1;
  for(i = 0; i < m; i++) {
    result *= n - i;
    result /= i + 1;
  }
  return result;
}

typedef struct isct {
  char *mask;
  int p_len;
  int *p;
} isct;

long int mask_intersect(char *mask1, char *mask2, char *mask_dest, int n) {

  int zero_count = 0;
  int any_count = 0;
  int i;
  for(i = 0; i < n; i++) {
    if(mask1[i] == '2') {
      mask_dest[i] = mask2[i];
    } else if (mask2[i] == '2') {
      mask_dest[i] = mask1[i];
    } else if (mask1[i] == mask2[i]) {
      mask_dest[i] = mask1[i];
    } else {
      return 0;
    }
    if(mask_dest[i] == '2') {
      any_count++;
    } else if (mask_dest[i] == '0') {
      zero_count++;
    }
  }
  if(zero_count > n/2 || any_count + zero_count < n/2) {
    return 0;
  }
  return binomial(any_count, n/2 - zero_count);
}

int main() {

  struct timespec start, end;
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);

  int n;
  scanf("%d", &n);
  int nn = 2 * n;

  int m = 0;
  int m_max = 1024;

  char **masks = malloc(m_max * sizeof(char *));

  while(1) {
    masks[m] = malloc(nn + 1);
    if (scanf("%s", masks[m]) == EOF) {
      break;
    }
    m++;
    if (m == m_max) {
      m_max *= 2;
      masks = realloc(masks, m_max * sizeof(char *));
    }
  }

  int i = 1;
  int i_max = 1024 * 128;

  isct *iscts = malloc(i_max * sizeof(isct));

  iscts[0].mask = malloc(nn);
  iscts[0].p = malloc(m * sizeof(int));

  int j;
  for(j = 0; j < nn; j++) {
    iscts[0].mask[j] = '2';
  }
  for(j = 0; j < m; j++) {
    iscts[0].p[j] = j;
  }
  iscts[0].p_len = m;

  int i_start = 0;
  int i_end = 1;
  int sign = 1;

  long int total = 0;

  int mask_bin_len = 1024 * 1024;
  char* mask_bin = malloc(mask_bin_len);
  int mask_bin_count = 0;

  int p_bin_len = 1024 * 128;
  int* p_bin = malloc(p_bin_len * sizeof(int));
  int p_bin_count = 0;


  while (i_end > i_start) {
    for (j = i_start; j < i_end; j++) {
      if (i + iscts[j].p_len > i_max) {
        i_max *= 2;
        iscts = realloc(iscts, i_max * sizeof(isct));
      }
      isct *isct_orig = iscts + j;
      int x;
      int x_len = 0;
      int i0 = i;
      for (x = 0; x < isct_orig->p_len; x++) {
        if(mask_bin_count + nn > mask_bin_len) {
          mask_bin_len *= 2;
          mask_bin = malloc(mask_bin_len);
          mask_bin_count = 0;
        }
        iscts[i].mask = mask_bin + mask_bin_count;
        mask_bin_count += nn;
        long int count =
            mask_intersect(isct_orig->mask, masks[isct_orig->p[x]], iscts[i].mask, nn);
        if (count > 0) {
          isct_orig->p[x_len] = isct_orig->p[x];
          i++;
          x_len++;
          total += sign * count;
        }
      }
      for (x = 0; x < x_len; x++) {
        int p_len = x_len - x - 1;
        iscts[i0 + x].p_len = p_len;
        if(p_bin_count + p_len > p_bin_len) {
          p_bin_len *= 2;
          p_bin = malloc(p_bin_len * sizeof(int));
          p_bin_count = 0;
        }
        iscts[i0 + x].p = p_bin + p_bin_count;
        p_bin_count += p_len;
        int y;
        for (y = 0; y < p_len; y++) {
          iscts[i0 + x].p[y] = isct_orig->p[x + y + 1];
        }
      }
    }

    sign *= -1;
    i_start = i_end;
    i_end = i;

  }

  printf("%lld\n", total);

  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);

  int seconds = end.tv_sec - start.tv_sec;
  long nanoseconds = end.tv_nsec - start.tv_nsec;
  if(nanoseconds < 0) {
    nanoseconds += 1000000000;
    seconds--;
  }

  printf("%d.%09lds\n", seconds, nanoseconds);
  return 0;
}

Casos de ejemplo:

robert@unity:~/c/se-mask$ gcc -O3 se-mask.c -lrt -o se-mask
robert@unity:~/c/se-mask$ head testcase-long
30
210211202222222211222112102111220022202222210122222212220210
010222222120210221012002220212102220002222221122222220022212
111022212212022222222220111120022120122121022212211202022010
022121221020201212200211120100202222212222122222102220020212
112200102110212002122122011102201021222222120200211222002220
121102222220221210220212202012110201021201200010222200221002
022220200201222002020110122212211202112011102220212120221111
012220222200211200020022121202212222022012201201210222200212
210211221022122020011220202222010222011101220121102101200122
robert@unity:~/c/se-mask$ ./se-mask < testcase-long
298208861472
0.001615834s
robert@unity:~/c/se-mask$ head testcase-hard
8
0222222222222222
1222222222222222
2022222222222222
2122222222222222
2202222222222222
2212222222222222
2220222222222222
2221222222222222
2222022222222222
robert@unity:~/c/se-mask$ ./se-mask < testcase-hard
12870
3.041261458s
robert@unity:~/c/se-mask$ 

(Los tiempos son para una CPU i7-4770K a 4.1 GHz.) Tenga cuidado, testcase-hardusa alrededor de 3-4 GB de memoria.

Esto es más o menos una implementación del método blutorange de inclusión-exclusión creado, pero hecho para que maneje las intersecciones de cualquier profundidad. El código tal como está escrito gasta mucho tiempo en la asignación de memoria, y se volverá aún más rápido una vez que optimice la administración de la memoria.

Ahorré alrededor de un 25% testcase-hard, pero el rendimiento en el original ( testcase-long) prácticamente no ha cambiado, ya que no hay mucha asignación de memoria allí. Voy a sintonizar un poco más antes de llamarlo: creo que también podría obtener una mejora del 25% al ​​50% testcase-long.

Mathematica

Una vez que noté que este era un problema de #SAT, me di cuenta de que podía usar el incorporado de Mathematica SatisfiabilityCount:

AbsoluteTiming[
 (* download test case *)
 input = Map[FromDigits, 
   Characters[
    Rest[StringSplit[
      Import["http://pastebin.com/raw.php?i=2Dg7gbfV", 
       "Text"]]]], {2}]; n = Length[First[input]];
 (* create boolean function *)
 bool = BooleanCountingFunction[{n/2}, n] @@ Array[x, n] && 
   Or @@ Table[
     And @@ MapIndexed[# == 2 || Xor[# == 1, x[First[#2]]] &, i], {i, 
      input}];
 (* count instances *)
 SatisfiabilityCount[bool, Array[x, n]]
]

Salida:

{1.296944, 298208861472}

Eso es 298,208,861,472 máscaras en 1.3 segundos (i7-3517U @ 1.9 GHz), incluido el tiempo dedicado a descargar el caso de prueba de pastebin.

Campeonato 2012
fuente
Así que he reescrito esto en C ... ¡desafortunadamente es demasiado rápido para mí usar gperftools en él! Encontraré algunos casos de prueba más difíciles antes de publicar mañana.
2012 Arcampion
testcase-hardpuede completarse muy rápidamente si su código busca máscaras que se puedan combinar. Si su código hace esto, elimine todas las demás líneas (por lo que solo /^2*02*$/quedan los casos). No creo que ese caso pueda optimizarse.
2012 Arcampion
4

rubí, bastante rápido, pero depende de la entrada

Ahora acelere por un factor de 2 ~ 2.5 cambiando de cadenas a enteros.

Uso:

cat <input> | ruby this.script.rb

P.ej.

mad_gaksha@madlab ~/tmp $ ruby c50138.rb < c50138.inp2
number of matches: 298208861472
took 0.05726237 s

El número de coincidencias para una sola máscara se calcula fácilmente por el coeficiente binomial. Entonces, por ejemplo, 122020necesita 3 2s llenos, 1 0y 2 1. Por lo tanto, hay nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3diferentes cadenas binarias que coinciden con esta máscara.

Una intersección entre n máscaras m_1, m_2, ... m_n es una máscara q, de modo que una cadena binaria s coincide con q solo si coincide con todas las máscaras m_i.

Si tomamos dos máscaras m_1 y m_2, su intersección se calcula fácilmente. Simplemente configure m_1 [i] = m_2 [i] si m_1 [i] == 2. La intersección entre 122020y 111222es 111020:

122020 (matched by 3 strings, 111000 110010 101010)
111222 (matched by 1 string, 111000)
111020 (matched by 1 string, 111000)

Las dos máscaras individuales se combinan con 3 + 1 = 4 cadenas, la máscara de intersección se corresponde con una cadena, por lo tanto, hay 3 + 1-1 = 3 cadenas únicas que coinciden con una o ambas máscaras.

Llamaré a N (m_1, m_2, ...) el número de cadenas que coinciden con todos m_i. Aplicando la misma lógica que la anterior, podemos calcular el número de cadenas únicas que coinciden con al menos una máscara, dada por el principio de exclusión de inclusión y ver a continuación también, así:

N(m_1) + N(m_2) + ... + N(m_n) - N(m_1,m_2) - ... - N(m_n-1,m_n) + N(m_1,m_2,m_3) + N(m_1,m_2,m_4) + ... N(m_n-2,m_n-1,m_n) - N(m_1,m_2,m_3,m_4) -+ ...

Hay muchas, muchas, muchas combinaciones de tomar, digamos 30 máscaras de 200.

Por lo tanto, esta solución supone que no existen muchas intersecciones de orden superior de las máscaras de entrada, es decir. La mayoría de las n-tuplas de n> 2 máscaras no tendrán coincidencias comunes.

Use el código aquí, el código de ideone puede estar desactualizado.

Agregué una función remove_duplicatesque se puede usar para preprocesar la entrada y eliminar máscaras de m_imodo que todas las cadenas que coincidan también coincidan con otra máscara m_j., Para la entrada actual, esto realmente lleva más tiempo ya que no hay tales máscaras (o no hay muchas) , por lo que la función aún no se aplica a los datos en el código a continuación.

Código:

# factorial table
FAC = [1]
def gen_fac(n)
  n.times do |i|
    FAC << FAC[i]*(i+1)
  end
end

# generates a mask such that it is matched by each string that matches m and n
def diff_mask(m,n)
  (0..m.size-1).map do |i|
    c1 = m[i]
    c2 = n[i]
    c1^c2==1 ? break : c1&c2
  end
end

# counts the number of possible balanced strings matching the mask
def count_mask(m)
  n = m.size/2
  c0 = n-m.count(0)
  c1 = n-m.count(1)
  if c0<0 || c1<0
    0
  else
    FAC[c0+c1]/(FAC[c0]*FAC[c1])
  end
end

# removes masks contained in another
def remove_duplicates(m)
  m.each do |x|
    s = x.join
    m.delete_if do |y|
      r = /\A#{s.gsub(?3,?.)}\Z/
      (!x.equal?(y) && y =~ r) ? true : false
    end
  end
end

#intersection masks of cn masks from m.size masks
def mask_diff_combinations(m,n=1,s=m.size,diff1=[3]*m[0].size,j=-1,&b)
  (j+1..s-1).each do |i|
    diff2 = diff_mask(diff1,m[i])
    if diff2
      mask_diff_combinations(m,n+1,s,diff2,i,&b) if n<s
      yield diff2,n
    end
  end
end

# counts the number of balanced strings matched by at least one mask
def count_n_masks(m)
  sum = 0
  mask_diff_combinations(m) do |mask,i|
    sum += i%2==1 ? count_mask(mask) : -count_mask(mask)
  end
  sum
end

time = Time.now

# parse input
d = STDIN.each_line.map do |line|
  line.chomp.strip.gsub('2','3')
end
d.delete_if(&:empty?)
d.shift
d.map!{|x|x.chars.map(&:to_i)}

# generate factorial table
gen_fac([d.size,d[0].size].max+1)

# count masks
puts "number of matches: #{count_n_masks(d)}"
puts "took #{Time.now-time} s"

Esto se llama el principio de exclusión de inclusión, pero antes de que alguien me lo señalara tenía mi propia prueba, así que aquí va. Sin embargo, hacer algo por ti mismo se siente genial.

Consideremos el caso de 2 máscaras, llame entonces 0y 1, primero. Tomamos todas las cadenas binarias balanceadas y las clasificamos de acuerdo con qué máscara (s) coinciden. c0es el número de aquellos que solo coinciden con la máscara 0, c1el número de aquellos que solo coinciden 1, c01los que coinciden con la máscara 0y 1.

Sea s0la suma numérica del número de coincidencias para cada máscara (pueden superponerse). Sea s1la suma de la cantidad de coincidencias para cada par (2 combinaciones) de máscaras. Sea s_ila suma del número de coincidencias para cada combinación de máscaras (i + 1). El número de coincidencias de n-máscaras es el número de cadenas binarias que coinciden con todas las máscaras.

Si hay n máscaras, la salida deseada es la suma de todas c, es decir. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Lo que calcula el programa es la suma alterna de todos s, es decir. s = s_0-s_1+s_2-+...+-s_(n-1). Queremos probar eso s==c.

n = 1 es obvio. Considere n = 2. Contando todos los partidos de la máscara 0da c0+c01(el número de cadenas que coinciden sólo 0 + coincidente tanto los 0e 1), contando todos los partidos del 1da c1+c02. Podemos ilustrar esto de la siguiente manera:

0: c0 c01
1: c1 c10

Por definición, s0 = c0 + c1 + c12. s1es el número total de coincidencias de cada combinación de 2 [0,1], es decir. todos uniqye c_ijs. Ten en cuenta eso c01=c10.

s0 = c0 + c1 + 2 c01
s1 = c01
s = s0 - s1 = c0 + c1 + c01 = c

Así s=cpara n = 2.

Ahora considere n = 3.

0  : c0 + c01 + c02 + c012
1  : c1 + c01 + c12 + c012
2  : c2 + c12 + c02 + c012
01 : c01 + c012
02 : c02 + c012
12 : c12 + c012
012: c012

s0 = c0 + c1 + c2 + 2 (c01+c02+c03) + 3 c012
s1 = c01 + c02 + c12 + 3 c012
s2 = c012

s0 = c__0 + 2 c__1 + 3 c__2
s1 =          c__1 + 3 c__2
s2 =                   c__2

s = s0 - s1 + s2 = ... = c0 + c1 + c2 + c01 + c02 + c03 + c012 = c__0 + c__1 + c__2 = c

Así s=cpara n = 3. c__irepresenta el de todos los cs con (i + 1) índices, por ejemplo, c__1 = c01para n = 2 y c__1 = c01 + c02 + c12para n == 3.

Para n = 4, un patrón comienza a emerger:

0:   c0 + c01 + c02 + c03 + c012 + c013 + c023 + c0123
1:   c1 + c01 + c12 + c13 + c102 + c103 + c123 + c0123
2:   c2 + c02 + c12 + c23 + c201 + c203 + c213 + c0123
3:   c3 + c03 + c13 + c23 + c301 + c302 + c312 + c0123

01:  c01 + c012 + c013 + c0123
02:  c02 + c012 + c023 + c0123
03:  c03 + c013 + c023 + c0123
12:  c11 + c012 + c123 + c0123
13:  c13 + c013 + c123 + c0123
23:  c23 + c023 + c123 + c0123

012:  c012 + c0123
013:  c013 + c0123
023:  c023 + c0123
123:  c123 + c0123

0123: c0123

s0 = c__0 + 2 c__1 + 3 c__2 + 4 c__3
s1 =          c__1 + 3 c__2 + 6 c__3
s2 =                   c__2 + 4 c__3
s3 =                            c__3

s = s0 - s1 + s2 - s3 = c__0 + c__1 + c__2 + c__3 = c

Así s==cpara n = 4.

En general, obtenemos coeficientes binomiales como este (↓ es i, → es j):

   0  1  2  3  4  5  6  .  .  .

0  1  2  3  4  5  6  7  .  .  .
1     1  3  6  10 15 21 .  .  .
2        1  4  10 20 35 .  .  .
3           1  5  15 35 .  .  .
4              1  6  21 .  .  .
5                 1  7  .  .  .
6                    1  .  .  . 
.                       .
.                          .
.                             .

Para ver esto, considere eso para algunos iy j, hay:

  • x = ncr (n, i + 1): combinaciones C para la intersección de la máscara (i + 1) de n
  • y = ncr (ni-1, ji): para cada combinación C anterior, existen y diferentes combinaciones para la intersección de (j + 2) máscaras de las que contienen C
  • z = ncr (n, j + 1): diferentes combinaciones para la intersección de (j + 1) máscaras de n

Como eso puede sonar confuso, aquí está la definición aplicada a un ejemplo. Para i = 1, j = 2, n = 4, se ve así (cf. arriba):

01:  c01 + c012 + c013 + c0123
02:  c02 + c012 + c023 + c0123
03:  c03 + c013 + c023 + c0123
12:  c11 + c012 + c123 + c0123
13:  c13 + c013 + c123 + c0123
23:  c23 + c023 + c123 + c0123

Entonces, aquí x = 6 (01, 02, 03, 12, 13, 23), y = 2 (dos c con tres índices para cada combinación), z = 4 (c012, c013, c023, c123).

En total, hay x*ycoeficientes ccon índices (j + 1), y hay zdiferentes, por lo que cada uno ocurre x*y/zveces, lo que llamamos coeficiente k_ij. Por álgebra simple, obtenemos k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).

Entonces, el índice está dado por k_ij = nCr(j+1,i+1)Si recuerda todas las definiciones, todo lo que necesitamos mostrar es que la suma alterna de cada columna da 1.

La suma alterna s0 - s1 + s2 - s3 +- ... +- s(n-1)se puede expresar como:

s_j = c__j * ∑[(-1)^(i+j) k_ij] for i=0..n-1
     = c__j * ∑[(-1)^(i+j) nCr(j+1,i+1)] for i=0..n-1
     = c__j * ∑[(-1)^(i+j) nCr(j+1,i)]{i=0..n} - (-1)^0 nCr(j+1,0)
     = (-1)^j c__j

s   = ∑[(-1)^j  s_j] for j = 0..n-1
    = ∑[(-1)^j (-1)^j c__j)] for j=0..n-1
    = ∑[c__j] for j=0..n-1
    = c

Así, s=cpara todos n = 1,2,3, ...

blutorange
fuente
1
No estoy seguro de saberlo, pero el método que está aplicando es en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle , por lo que no tiene que demostrarlo, si esto es lo que está tratando de hacer. hacer. Además, si bien no es necesario para los casos de prueba, puede eliminar de los grupos máscaras que están completamente incluidas en otra máscara del grupo. Por ejemplo en TC5: 0011 < 2211, 0022 < 0222. Creo que esto hace que los grupos no sean más grandes 2*n, aunque todavía es demasiado grande en el peor de los casos.
nutki
@nutki No había sido consciente de esto, así que gracias por el enlace. Ocasionalmente, probar y pensar en algo para uno mismo sigue siendo un buen ejercicio, sin embargo :). En cuanto a su sugerencia, sí, se me ocurrió hacerlo, pero no creo que vaya a implementarlo a menos que se agregue un caso de prueba que requiera que obtenga el resultado en un período de tiempo razonable.
blutorange
@blutorange ¿pensaste en usar el árbol de decisión?
Abr001am
Creo que te refieres a la intersección (coincide con ambas máscaras), no a la unión (coincide con una u otra máscara).
2012 Arcampion
@ 2012 Arcampion Como en unifying two masksel término uniontiene sentido para mí y puedo definirlo de esa manera, pero tienes razón, en aras del entendimiento mutuo que he criticado. @ Agawa001 ¿Puedes ser más específico? Además, si tiene alguna buena idea para hacer esto más rápido, siéntase libre de usar cualquier idea de esta respuesta para su programa / respuesta. Por ahora, es lo suficientemente rápido para el caso de prueba grande, y si se hace con subprocesos múltiples, debería tomar <0.1s, que está por debajo de cualquier medición / comparación significativa, por lo que se necesitan casos de prueba más difíciles.
blutorange
1

C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gsl/gsl_combination.h>

int main (int argc, char *argv[]) {

    printf ("reading\n");
    char buffer[100];
    gets(buffer);
    char n = atoi(buffer);

    char *masks[1000];
    masks[0] = malloc(2 * n * sizeof(char));
    char c,nrows,j,biggestzerorun,biggestonerun,currentzerorun,currentonerun = 0;

    while ((c = getchar()) && c != EOF) {
        if (c == '\n') {
            nrows++;
            if (currentonerun > biggestonerun) {
                biggestonerun = currentonerun;
            }
            if (currentzerorun > biggestzerorun) {
                biggestzerorun = currentzerorun;
            }
            j=currentonerun=currentzerorun=0;
            masks[nrows] = malloc(2 * n * sizeof(char));
        } else if (c == '0') {
            masks[nrows][j++] = 1;
            currentzerorun++;
            if (currentonerun > biggestonerun) {
                biggestonerun = currentonerun;
            }
            currentonerun=0;
        } else if (c == '1') {
            masks[nrows][j++] = 2;
            currentonerun++;
            if (currentzerorun > biggestzerorun) {
                biggestzerorun = currentzerorun;
            }
            currentonerun=0;
        } else if (c == '2') {
            masks[nrows][j++] = 3;
            currentonerun++;
            currentzerorun++;
        }
    }
    if (currentonerun > biggestonerun) {
        biggestonerun = currentonerun;
    }
    if (currentzerorun > biggestzerorun) {
        biggestzerorun = currentzerorun;
    }

    printf("preparing combinations\n");

    int nmatches=0;

    gsl_combination *combination = gsl_combination_calloc(2*n, n);

    printf("entering loop:\n");

    do {
        char vector[2*n];
        char currentindex, previousindex;
        currentonerun = 0;
        memset(vector, 1, 2*n);


        // gsl_combination_fprintf (stdout, combination, "%u ");
        // printf(": ");

        for (char k=0; k<n; k++) {
            previousindex = currentindex;
            currentindex = gsl_combination_get(combination, k);
            if (k>0) {
                if (currentindex - previousindex == 1) {
                    currentonerun++;
                    if (currentonerun > biggestonerun) {
                        goto NEXT;
                    }
                } else {
                    currentonerun=0;
                    if (currentindex - previousindex > biggestzerorun) {
                        goto NEXT;
                    }
                }
            }
            vector[currentindex] = 2;
        }

        for (char k=0; k<=nrows; k++) {
            char ismatch = 1;
            for (char l=0; l<2*n; l++) {
                if (!(vector[l] & masks[k][l])) {
                    ismatch = 0;
                    break;
                }
            }
            if (ismatch) {
                nmatches++;
                break;
            }
        }

        NEXT: 1;

    } while (
        gsl_combination_next(combination) == GSL_SUCCESS
    );

    printf ("RESULT: %i\n", nmatches);

    gsl_combination_free(combination);
    for (; nrows>=0; nrows--) {
        free(masks[nrows]);
    }
}

Buena suerte para obtener el gran aporte para ejecutar esto: probablemente tomará toda la noche superar aprox. 60 ^ 30 permutaciones! ¿Quizás un conjunto de datos de tamaño intermedio podría ser una buena idea?

alexander-brett
fuente