Contare le stringhe binarie bilanciate corrispondenti a qualsiasi set di maschere


10

Una stringa binaria è una stringa che contiene solo caratteri disegnati da 01 . Una stringa binaria bilanciata è una stringa binaria che contiene esattamente 0 s come 1 s.

Ti viene dato un numero intero positivo n e un numero arbitrario di maschere, ciascuna delle quali è lunga 2n caratteri e contiene solo caratteri disegnati da 012 . Una stringa binaria e una maschera corrispondono se hanno la stessa lunghezza e concordano sul personaggio in ogni posizione in cui la maschera non ha un 2 . Ad esempio, la maschera 011022 corrisponde alle stringhe binarie 011000 , 011001 , 011010 , 011011 .

Dati n e le maschere come input (separati da nuove righe), è necessario generare il numero di stringhe binarie bilanciate distinte che corrispondono a una o più maschere.

Esempi

Ingresso

3
111222
000112
122020
122210
102120

Ragionamento

  • L'unica stringa binaria bilanciata corrispondente a 111222 è 111000 .
  • L'unica stringa binaria bilanciata corrispondente a 000112 è 000111 .
  • Le stringhe binarie bilanciate corrispondenti a 122020 sono 111000 (già contate), 110010 e 101010 .
  • Le stringhe binarie bilanciati corrispondenza a 122.210 sono 110010 (già contati), 101010 (già conteggiati) e 100110 .
  • Le stringhe binarie bilanciate corrispondenti a 102120 sono 101100 e 100110 (già conteggiate).

Quindi l'output dovrebbe essere

6

Ingresso

10
22222222222222222222

Ragionamento

  • Ci sono 20 scegliere 10 stringhe binarie bilanciate di lunghezza 20.

Produzione

184756

Vincitore

Il vincitore sarà quello che calcolerà l'input della competizione più velocemente, ovviamente trattandolo allo stesso modo di qualsiasi altro input. (Uso un determinato codice per avere un chiaro vincitore ed evitare casi in cui input diversi darebbero vincitori diversi. Se pensi a un modo migliore per trovare il codice più veloce, dimmelo).

Contributo alla competizione

http://pastebin.com/2Dg7gbfV


2
Inoltre, personalmente preferisco vivamente gist.github.com rispetto a pastebin, sia per l'estetica che per i difetti futuri.
orlp,

3
@AlbertMasclans Penso che dovresti riservarti il ​​diritto di modificare l'input. Altrimenti, qualcuno può codificare l'output.
mbomb007,

1
Sarebbe utile se potessi pubblicare un piccolo esempio nella domanda, con il risultato atteso e una spiegazione. Potrei essere solo lento, ma non riesco proprio a ottenere la definizione. Quindi, per esempio, poiché n = 30, stiamo cercando sequenze di 30 0 o 30 1 (con 2 come carattere jolly) in qualsiasi riga? Queste sequenze possono sovrapporsi? Ad esempio, se trovo una sequenza di 32 1s, conta come 3 sequenze o come singola sequenza? Cosa succede se trovo una sequenza di 60 1 (riga intera)? È 1 sequenza, 2 sequenze o 31 sequenze?
Reto Koradi,

3
Quindi stai chiedendo il numero di array univoci in questa matrice che hanno uguali numeri di 1 e 0, giusto?
ASCIIThenANSI

1
Possiamo avere altri dati di test per favore?
alexander-brett,

Risposte:


2

C

Se non sei su Linux o hai problemi a compilare, probabilmente dovresti rimuovere il codice di temporizzazione ( 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;
}

Casi di esempio:

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$ 

(I tempi sono per una CPU i7-4770K a 4,1 GHz.) Fai attenzione, testcase-hardutilizza circa 3-4 GB di memoria.

Si tratta praticamente di un'implementazione del metodo blutorange di inclusione-esclusione, ma fatto in modo da gestire intersezioni di qualsiasi profondità. Il codice scritto sta impiegando molto tempo nell'allocazione della memoria e diventerà ancora più veloce una volta ottimizzato la gestione della memoria.

Mi sono rasato il 25% circa testcase-hard, ma le prestazioni sull'originale ( testcase-long) sono praticamente invariate, poiché non c'è molta allocazione di memoria lì. Ottimizzerò un po 'di più prima di chiamarlo: penso che potrei essere in grado di ottenere anche un miglioramento del 25% -50% testcase-long.

matematica

Una volta notato che si trattava di un problema #SAT, mi sono reso conto che avrei potuto usare il built-in di 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]]
]

Produzione:

{1.296944, 298208861472}

Sono 298.208.861.472 maschere in 1,3 secondi (i7-3517U @ 1,9 GHz), incluso il tempo impiegato per scaricare il test case da pastebin.


Quindi l'ho riscritto in C ... sfortunatamente è troppo veloce per me usare gperftools! Troverò alcuni casi più difficili prima di pubblicare domani.
Campionato 2012

testcase-hardpuò essere completato molto rapidamente se il tuo codice cerca maschere che possono essere combinate. Se il tuo codice fa questo, allora elimina ogni altra riga (quindi /^2*02*$/rimangono solo i casi). Non credo che il caso possa essere ottimizzato.
Campionato 2012

4

rubino, abbastanza veloce, ma dipende dall'input

Ora accelera di un fattore 2 ~ 2,5 passando da stringhe a numeri interi.

Uso:

cat <input> | ruby this.script.rb

Per esempio.

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

Il numero di corrispondenze per una singola maschera viene facilmente calcolato dal coefficiente binomiale. Quindi ad esempio ha 122020bisogno di 3 2s riempiti, 1 0e 2 1. Quindi ci sono nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3diverse stringhe binarie che corrispondono a questa maschera.

Un'intersezione tra n maschere m_1, m_2, ... m_n è una maschera q, tale che una stringa binaria s corrisponde a q solo se corrisponde a tutte le maschere m_i.

Se prendiamo due maschere m_1 e m_2, la sua intersezione viene facilmente calcolata. Basta impostare m_1 [i] = m_2 [i] se m_1 [i] == 2. L'intersezione tra 122020e 111222è 111020:

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

Le due maschere individuali sono abbinate da 3 + 1 = 4 stringhe, la maschera di intersezione è abbinata da una stringa, quindi ci sono 3 + 1-1 = 3 stringhe uniche che corrispondono a una o entrambe le maschere.

Chiamerò N (m_1, m_2, ...) il numero di stringhe corrispondenti a tutti i m_i. Applicando la stessa logica di cui sopra, possiamo calcolare il numero di stringhe univoche associate a almeno una maschera, dato dal principio di esclusione dell'inclusione e vedere anche di seguito, in questo modo:

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

Ci sono molte, molte, molte combinazioni di prendere, diciamo 30 maschere su 200.

Quindi questa soluzione presuppone che non esistano molte intersezioni di ordine elevato delle maschere di input, vale a dire. la maggior parte delle n-tuple di n> 2 maschere non avranno corrispondenze comuni.

Usa qui il codice, il codice su ideone potrebbe non essere aggiornato.

Ho aggiunto una funzione remove_duplicatesche può essere utilizzata per pre-elaborare l'input ed eliminare le maschere in modo m_itale che tutte le stringhe che corrispondono ad essa corrispondano anche a un'altra maschera m_j. , quindi la funzione non è ancora applicata ai dati nel codice seguente.

Codice:

# 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"

Questo si chiama principio di esclusione dell'inclusione, ma prima che qualcuno me lo indicasse avevo la mia prova, quindi eccola. Fare qualcosa da soli è comunque fantastico.

Consideriamo il caso di 2 maschere, chiama quindi 0e 1, prima. Prendiamo ogni stringa binaria bilanciata e la classifichiamo in base alla maschera o alle maschere corrispondenti. c0è il numero di quelli che corrispondono solo alla maschera 0, c1il numero di quelli che corrispondono solo 1, c01quelli che corrispondono alla maschera 0e 1.

Sia s0la somma numerica del numero di corrispondenze per ciascuna maschera (possono sovrapporsi). Sia s1la somma del numero di corrispondenze per ciascuna coppia (2 combinazioni) di maschere. Sia s_ila somma del numero di corrispondenze per ciascuna (i + 1) combinazione di maschere. Il numero di corrispondenze di n-maschere è il numero di stringhe binarie che corrispondono a tutte le maschere.

Se ci sono n maschere, l'output desiderato è la somma di tutti c, cioè. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Ciò che il programma calcola è la somma alternata di tutti s, vale a dire. s = s_0-s_1+s_2-+...+-s_(n-1). Vogliamo dimostrarlo s==c.

n = 1 è ovvio. Considera n = 2. Contando tutte le partite di maschera 0c0+c01(il numero di stringhe corrisponde solo a 0 + quelle che corrispondono a entrambe 0e 1), contando tutte le partite di 1c1+c02. Possiamo illustrarlo come segue:

0: c0 c01
1: c1 c10

Per definizione, s0 = c0 + c1 + c12. s1è il numero totale di corrispondenze di ciascuna combinazione 2 di [0,1], ad es. tutti uniqye c_ijs. Tienilo a mente c01=c10.

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

Quindi s=cper n = 2.

Ora considera 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

Quindi s=cper n = 3. c__irappresenta la di tutte le cs con (i + 1) indici, ad esempio c__1 = c01per n = 2 e c__1 = c01 + c02 + c12per n == 3.

Per n = 4, inizia a emergere un modello:

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

Quindi s==cper n = 4.

In generale, otteniamo coefficienti binomiali come questo (↓ è i, → è 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  .  .  . 
.                       .
.                          .
.                             .

Per vedere questo, considera che per alcuni ie jci sono:

  • x = ncr (n, i + 1): combinazioni C per l'intersezione della maschera (i + 1) da n
  • y = ncr (ni-1, ji): per ogni combinazione C sopra, ci sono y diverse combinazioni per l'intersezione di (j + 2) maschere da quelle che contengono C
  • z = ncr (n, j + 1): diverse combinazioni per l'intersezione di (j + 1) maschere da n

Poiché ciò può sembrare confuso, ecco la definizione applicata a un esempio. Per i = 1, j = 2, n = 4, è simile al seguente (vedi sopra):

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

Quindi qui x = 6 (01, 02, 03, 12, 13, 23), y = 2 (due c con tre indici per ogni combinazione), z = 4 (c012, c013, c023, c123).

In totale, ci sono x*ycoefficienti ccon (j + 1) indici, e ce ne sono zdiversi, quindi ognuno si verifica per x*y/ztempi, che chiamiamo coefficiente k_ij. Con una semplice algebra, otteniamo k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).

Quindi l'indice è dato da k_ij = nCr(j+1,i+1)Se ricordi tutte le definizioni, tutto ciò che dobbiamo mostrare è che la somma alternata di ogni colonna dà 1.

La somma alternata s0 - s1 + s2 - s3 +- ... +- s(n-1)può quindi essere espressa come:

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

Quindi s=cper tutti n = 1,2,3, ...


1
Non sono sicuro che tu sia a conoscenza, ma il metodo che stai applicando è en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle , quindi non devi provarlo, se questo era quello che stai cercando di fare. Inoltre, anche se non è necessario per i casi di test, è possibile eliminare dalle maschere dei gruppi che sono completamente incluse in un'altra maschera nel gruppo. Ad esempio in TC5: 0011 < 2211, 0022 < 0222. Penso che questo non renda i gruppi più grandi di 2*n, sebbene sia ancora troppo grande nel caso peggiore.
Nutki,

@nutki non me ne ero accorto, quindi grazie per il link. Occasionalmente, provare e pensare a qualcosa per se stessi è comunque un esercizio piacevole :). Per quanto riguarda il tuo suggerimento, sì, mi era venuto in mente di farlo, ma non credo che lo implementerò a meno che non venga aggiunto un caso di test che lo richiede per ottenere il risultato in un ragionevole lasso di tempo.
Blutorange,

@blutorange hai pensato di usare l'albero delle decisioni?
Abr001,

Penso che tu intenda l' intersezione (corrisponde a entrambe le maschere), non l' unione (corrisponde all'una o all'altra maschera).
Campionato 2012

@ 2012rcampion Come nel unifying two maskstermine unionha senso per me e io xan lo definisco in questo modo, ma hai ragione, nell'interesse della comprensione reciproca che ho criticato. @ Agawa001 Puoi essere più specifico? Inoltre, se hai qualche buona idea per renderlo più veloce, sentiti libero di usare qualsiasi idea da questa risposta per il tuo programma / risposta. Per ora, è abbastanza veloce per il caso di test di grandi dimensioni e, se realizzato in multi-thread, dovrebbe richiedere <0,1 s, che è inferiore a qualsiasi misurazione / confronto significativi, quindi per casi di test più difficili sono necessari.
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]);
    }
}

Buona fortuna per ottenere il grande input da eseguire su questo - probabilmente ci vorrà tutta la notte per superare ca. 60 ^ 30 permutazioni! Forse un set di dati di dimensioni intermedie potrebbe essere una buona idea?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.