Bir dizi maskeyle eşleşen dengeli ikili dizeleri sayın


10

Bir ikili dize çekilen tek karakterler içeren bir dizedir 01 . Bir dengeli ikili dize tam Birçok olarak içeren bir ikili dizedir 0 olarak s 1 s.

Sen pozitif bir tamsayı verilir n ve her biri maskelerinin rastgele sayıda, 2n uzun karakterler ve çekilen tek karakterler içeriyor 012 . İkili bir dize ve maske, aynı uzunluktaysa ve maskenin 2 olmadığı her konumdaki karaktere katılırsa eşleşir . Örneğin, maske 011022 011000 , 011001 , 011010 , 011011 ikili dizeleriyle eşleşir .

N ve maskeler girdi olarak (satırsonu ile ayrılmış olarak) verildiğinde , maskelerden bir veya daha fazlasıyla eşleşen farklı dengeli ikili dizelerin sayısını çıkarmalısınız.

Örnekler

Giriş

3
111222
000112
122020
122210
102120

muhakeme

  • 111222 ile eşleşen tek dengeli ikili dize 111000'dir .
  • 000112 ile eşleşen tek dengeli ikili dize 000111'dir .
  • 122020 ile eşleşen dengeli ikili dizgiler 111000 (zaten sayılmış), 110010 ve 101010'dur .
  • Eşleşen dengeli ikili dizeleri 122210 olan 110.010 (önceden sayılmış), 101.010 (önceden sayılmış) ve 100.110 .
  • Eşleşen dengeli ikili dizeleri 102120 olan 101.100 ve 100.110 (önceden sayılmış).

Yani çıktı

6

Giriş

10
22222222222222222222

muhakeme

  • Orada 20 10 seçim uzunluğu 20 dengeli ikili dizeleri.

Çıktı

184756

kazanan

Kazanan, rekabet girdisini en hızlı hesaplayan, tabii ki diğer girdiler gibi davranacak. (Açık bir kazanan elde etmek ve farklı girdilerin farklı kazananlara vereceği durumlardan kaçınmak için belirli bir kod kullanıyorum. En hızlı kodu bulmanın daha iyi bir yolunu düşünüyorsanız, bana söyleyin).

Yarışma girdisi

http://pastebin.com/2Dg7gbfV


2
Ayrıca, şahsen gist.github.com'u hem estetik hem de gelecekteki hatalar için macun yerine tercih ederim .
orlp

3
@AlbertMasclans Sanırım girişi değiştirme hakkını saklı tutmalısınız. Aksi takdirde, biri çıktıyı kodlayabilir.
mbomb007

1
Soruda, beklenen sonuç ve bir açıklama ile küçük bir örnek gönderebilmeniz yararlı olacaktır. Sadece yavaş olabilirim, ama tanımı tam olarak anlayamıyorum. Yani, örnek olarak, n = 30 olduğundan, herhangi bir satırda 30 0 veya 30 1 (2 joker karakter olmak üzere) dizileri mi arıyoruz? Bu diziler çakışabilir mi? Örneğin, 32 l'lik bir dizi bulursam, bu 3 dizi veya tek bir dizi olarak sayılır mı? Ya 60 1 saniyelik bir sıra bulursam (tüm satır)? Bu 1 dizi, 2 dizi veya 31 dizi mi?
Reto Koradi

3
Yani bu matristeki eşit sayıda 1 ve 0'a sahip benzersiz dizilerin sayısını istiyorsunuz, değil mi?
ASCIIThenANSI

1
Daha fazla test verisi alabilir miyiz lütfen?
alexander-brett

Yanıtlar:


2

C

Linux'ta değilseniz veya derleme konusunda sorun yaşıyorsanız, muhtemelen zamanlama kodunu ( clock_gettime) kaldırmalısınız .

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

Örnek durumlar:

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$ 

(Zamanlar 4.1 GHz'de i7-4770K CPU içindir.) Dikkatli olun, testcase-hardyaklaşık 3-4 GB bellek kullanır.

Bu, hemen hemen dahil etme-hariç tutma yönteminin bir uygulamasıdır ve blutorange ortaya çıktı, ancak herhangi bir derinliğin kavşaklarını ele alacak şekilde yapıldı. Yazıldığı gibi kod bellek ayırma için çok zaman harcıyor ve bellek yönetimini optimize ettikten sonra daha da hızlı olacak.

Yaklaşık% 25'i traş ettim testcase-hard, ancak orijinalde ( testcase-long) performans değişmedi, çünkü fazla bellek ayırma gerçekleşmiyor. Ben çağırmadan önce biraz daha ayarlayacağım: Sanırım% 25-% 50 oranında bir iyileşme elde edebilirim testcase-long.

Mathematica

Bunun #SAT sorunu olduğunu fark ettiğimde, Mathematica'nın yerleşik özelliğini kullanabileceğimi fark ettim 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]]
]

Çıktı:

{1.296944, 298208861472}

Bu, test senaryosunu pastebin'den indirmek için harcanan zaman da dahil olmak üzere 1.3 saniyede 298.208.861.472 maskedir (i7-3517U @ 1.9 GHz).


Bu yüzden bunu C'de yeniden yazdım ... maalesef üzerinde gperftools kullanmam çok hızlı! Yarın göndermeden önce bazı zor test örnekleri bulacağım.
2012rampiyon

testcase-hardkodunuz birleştirilebilecek maskeler ararsa çok hızlı bir şekilde tamamlanabilir. Kodunuz bunu yaparsa, diğer tüm satırları silin (yalnızca /^2*02*$/durumlar devam eder). Bu davanın optimize edilebileceğini düşünmüyorum.
2012rampiyon

4

yakut, oldukça hızlı, ancak girdiye bağlı

Şimdi dizelerden tamsayılara geçerek 2 ~ 2,5 faktör hızlandırın.

Kullanımı:

cat <input> | ruby this.script.rb

Örneğin.

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

Binom katsayısı tarafından kolayca hesaplanan tek bir maske için eşleşme sayısı. Yani örneğin 1220203 2s dolu, 1 0ve 2 gerekir 1. Bu yüzden nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3bu maskeyle eşleşen farklı ikili dizeler vardır .

N maskeleri m_1, m_2, ... m_n arasındaki kesişme bir maske q'dur, öyle ki ikili bir s dizisi sadece m_i tüm maskelerle eşleştiğinde q ile eşleşir.

İki maske m_1 ve m_2 alırsak, kesişimi kolayca hesaplanır. M_1 [i] == 2 ise m_1 [i] = m_2 [i] ayarını yapmanız yeterlidir. Kesişme 122020ve 111222bir 111020:

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

İki ayrı maske 3 + 1 = 4 dize ile eşleştirilir, kesişim maskesi bir dize ile eşleştirilir, bu nedenle bir veya her iki maskle eşleşen 3 + 1-1 = 3 benzersiz dize vardır.

Tüm m_i ile eşleşen dizelerin sayısını N (m_1, m_2, ...) olarak arayacağım. Yukarıdaki ile aynı mantığı uygulayarak, dahil etme hariç tutma ilkesi tarafından verilen en az bir maske ile eşleşen benzersiz dizelerin sayısını hesaplayabilir ve aşağıdaki gibi de görebilirsiniz:

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

200'den 30 maske almanın birçok, birçok, birçok kombinasyonları var.

Böylece bu çözüm, giriş maskelerinin pek çok üst düzey kesişiminin olmadığı varsayımını yapar. n> 2 maskesinin çoğu n-tuplesinde ortak bir eşleşme olmaz.

Buradaki kodu kullanın, ideone'deki kod eski olabilir.

remove_duplicatesGiriş işlemek ve m_ionunla eşleşen tüm dizeleri de başka bir maske ile eşleşecek şekilde maskeleri silmek için kullanılabilecek bir işlev ekledim m_j., Geçerli giriş için, bu tür maskeler (veya çok fazla) olmadığı için bu aslında daha uzun sürer , bu nedenle işlev henüz aşağıdaki koddaki verilere uygulanmaz.

Kod:

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

Buna dahil etme dışlama ilkesi denir, ancak biri beni işaret etmeden önce kendi kanıtım vardı, işte gidiyor. Kendiniz bir şey yapmak harika hissettiriyor.

İki maskeyi ele alalım, sonra arayın 0ve 1önce. Her dengeli ikili dizeyi alıp, hangi maskeye (maskelere) uygun olduğunu sınıflandırıyoruz. c0maske sadece maç olanların sayısıdır 0, c1sadece maç olanların Nunber 1, c01bu o maç maske 0ve 1.

Izin vermek s0her maske için maç sayısı toplamı (onlar örtüşebilir). Izin vermek s1her çifti (2-kombinasyonu) için eşleşme sayısı toplamı maskeleri. Izin vermek s_iher (i + 1) maske kombinasyonu için maç sayısı toplamı. N maskelerinin eşleşme sayısı, tüm maskelerle eşleşen ikili dizelerin sayısıdır.

Eğer n maske varsa, istenen çıktı tümünün toplamıdır c, yani. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Programın hesapladığı şey, hepsinin alternatif toplamıdır s. s = s_0-s_1+s_2-+...+-s_(n-1). Bunu kanıtlamak istiyoruz s==c.

n = 1 açıktır. N = 2'yi düşünün. Maskenin tüm eşleşmeleri Sayma 0verir c0+c01(sadece 0 + olanlar eşleştirme hem eşleşen dizeleri sayısını 0ve 1her eşleşmeleri sayarak,) 1verir c1+c02. Bunu şu şekilde açıklayabiliriz:

0: c0 c01
1: c1 c10

Tanımı gereği s0 = c0 + c1 + c12,. s1her 2 kombinasyonunun toplam eşleşme sayısıdır [0,1], yani. tüm uniqye c_ijs. Unutmayın c01=c10.

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

Böylece s=cn = 2 için.

Şimdi n = 3'ü düşünün.

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

Böylece s=cn = 3 için. (i + 1) indeksli c__itüm cs'leri temsil eder , örneğin c__1 = c01n = 2 ve c__1 = c01 + c02 + c12n == 3 için.

N = 4 için, bir desen ortaya çıkmaya başlar:

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

Böylece s==cn = 4 için.

Genel olarak, bunun gibi binom katsayıları elde ederiz (↓, 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  .  .  . 
.                       .
.                          .
.                             .

Bunu görmek için, bazıları için bunu düşünün ive jvar:

  • x = ncr (n, i + 1): (i + 1) maskesinin n dışında kesişimi için C kombinasyonları
  • y = ncr (ni-1, ji): yukarıdaki her C kombinasyonu için, (j + 2) maskelerinin C içerenlerden kesişimi için y farklı kombinasyon vardır.
  • z = ncr (n, j + 1): (j + 1) maskelerinin n dışında kesişimi için farklı kombinasyonlar

Bu kafa karıştırıcı gelebilir, işte bir örnek için uygulanan tanım. İ = 1, j = 2, n = 4 için, şuna benzer (yukarıdaki referans):

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

Yani burada x = 6 (01, 02, 03, 12, 13, 23), y = 2 (her kombinasyon için üç indeksi olan iki c), z = 4 (c012, c013, c023, c123).

Toplamda, (j + 1) indeksleri olan x*ykatsayılar cvardır ve zfarklı olanlar vardır, bu nedenle her biri x*y/zkatsayı dediğimiz zamanlar meydana gelir k_ij. Basit cebirle anlıyoruz k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).

Dizin tarafından verilir. k_ij = nCr(j+1,i+1)Tüm tanımları hatırlarsanız, göstermemiz gereken tek şey, her sütunun alternatif toplamının 1 vermesidir.

Alternatif toplam s0 - s1 + s2 - s3 +- ... +- s(n-1), böylece şu şekilde ifade edilebilir:

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

Böylece s=ctüm n = 1,2,3, ...


1
Farkında olup olmadığınızdan emin değilim, ancak uyguladığınız yöntem en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle olduğundan , kanıtlamak zorunda değilsiniz, eğer denediğiniz şey buysa yapmak. Ayrıca test durumları için gerekli olmasa da, gruptaki başka bir maskeye tamamen dahil olan grup maskelerini ortadan kaldırabilirsiniz. Örneğin TC5'te: 0011 < 2211, 0022 < 0222. 2*nEn kötü durumda hala çok büyük olmasına rağmen , bu grupların daha büyük olmadığını düşünüyorum .
nutki

@nutki Bunun farkında değildim, bu yüzden bağlantı için teşekkürler. Ara sıra, kendini kanıtlamak ve kendisi için bir şeyler düşünmek yine de güzel bir alıştırmadır :). Önerilerinize gelince, evet, bunu yapmak benim için gerçekleşti, ancak makul bir süre içinde sonuç almasını gerektiren bir test örneği eklenmedikçe uygulayacağımı sanmıyorum.
blutorange

@blutorange u karar ağacı kullanmayı düşündün mü?
Abr001am

Sanırım birleşim (bir veya diğer maskeyle eşleşir ) değil kavşak (her iki maskeyle eşleşir ) demek istediniz .
2012rampiyon

İçinde 2012rcampion As @ unifying two masksvadede unionbana mantıklı ve bu şekilde tanımlamak Xan, ancak ben chabged ettik karşılıklı anlayış yararına, haklısın. @ Agawa001 Daha spesifik olabilir misiniz? Ayrıca, bunu daha hızlı hale getirmek için iyi bir fikriniz varsa, programınız / cevabınız için bu cevaptaki fikirleri kullanmaktan çekinmeyin. Şimdilik, büyük test durumu için yeterince hızlıdır ve çok iş parçacıklı yapılırsa, anlamlı bir ölçüm / karşılaştırmanın altında olan <0.1s almalıdır, bu nedenle daha sert test durumları için gereklidir.
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]);
    }
}

Bu konuda çalıştırmak için büyük bir giriş elde etmek iyi şanslar - muhtemelen yaklaşık tüm gece sürecek. 60 ^ 30 permütasyon! Belki orta büyüklükte bir veri kümesi iyi bir fikir olabilir?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.