Đếm các chuỗi nhị phân cân bằng phù hợp với bất kỳ bộ mặt nạ nào


10

Một chuỗi nhị phân là một chuỗi có chứa các ký tự rút ra từ 01 . Một chuỗi nhị phân cân là một chuỗi nhị phân, trong đó có chính xác như nhiều 0 s là 1 s.

Bạn được cấp một số nguyên dương n và số mặt nạ tùy ý, mỗi số có độ dài 2n ký tự và chỉ chứa các ký tự được vẽ từ 012 . Một chuỗi nhị phân và mặt nạ khớp với nhau nếu nó có cùng độ dài và đồng ý với ký tự ở mọi vị trí mà mặt nạ không có 2 . Ví dụ như mặt nạ 011.022 trận đấu các chuỗi nhị phân 011.000 , 011.001 , 011.010 , 011.011 .

Cho n và mặt nạ làm đầu vào (cách nhau bởi dòng mới), bạn phải xuất số chuỗi nhị phân cân bằng riêng biệt khớp với một hoặc nhiều mặt nạ.

Ví dụ

Đầu vào

3
111222
000112
122020
122210
102120

Lý luận

  • Chuỗi nhị phân cân bằng duy nhất phù hợp với 111222111000 .
  • Chuỗi nhị phân cân bằng duy nhất phù hợp với 000112000111 .
  • Các chuỗi nhị phân cân phù hợp với 122.020111.000 (đã tính), 110.010101.010 .
  • Các chuỗi nhị phân cân bằng phù hợp với 122210110010 (đã được tính), 101010 (đã được tính) và 100110 .
  • Các chuỗi nhị phân cân bằng phù hợp với 102120101100100110 (đã được tính).

Vì vậy, đầu ra nên được

6

Đầu vào

10
22222222222222222222

Lý luận

  • 20 chọn 10 chuỗi nhị phân cân bằng có độ dài 20.

Đầu ra

184756

Người chiến thắng

Người chiến thắng sẽ là người tính toán đầu vào cạnh tranh nhanh nhất, tất nhiên đối xử với nó giống như bất kỳ đầu vào nào khác. (Tôi sử dụng một mã xác định để có một người chiến thắng rõ ràng và tránh các trường hợp trong đó các đầu vào khác nhau sẽ cho những người chiến thắng khác nhau. Nếu bạn nghĩ ra một cách tốt hơn để tìm mã nhanh nhất, hãy nói với tôi như vậy).

Đầu vào cạnh tranh

http://pastebin.com/2Dg7gbfV


2
Ngoài ra, cá nhân tôi rất thích gist.github.com hơn pastebin, cả về tính thẩm mỹ và lỗi trong tương lai.
orlp

3
@AlbertMasclans Tôi nghĩ bạn nên bảo lưu quyền thay đổi đầu vào. Nếu không, ai đó có thể mã hóa đầu ra.
mbomb007

1
Sẽ rất hữu ích nếu bạn có thể đăng một ví dụ nhỏ trong câu hỏi, với kết quả mong đợi và một lời giải thích. Tôi có thể chậm, nhưng tôi không hiểu rõ lắm. Vì vậy, ví dụ, vì n = 30, chúng tôi đang tìm kiếm các chuỗi 30 0 hoặc 30 1 (với 2 là ký tự đại diện) trong bất kỳ hàng nào? Những trình tự có thể chồng lên nhau? Ví dụ: nếu tôi tìm thấy một chuỗi 32 1 giây, thì đó có phải là 3 chuỗi hay là một chuỗi không? Điều gì xảy ra nếu tôi tìm thấy một chuỗi 60 1s (toàn bộ hàng)? Đó có phải là 1 chuỗi, 2 chuỗi hay 31 chuỗi?
Reto Koradi

3
Vì vậy, bạn đang yêu cầu số lượng mảng duy nhất trong ma trận này có số lượng bằng 1 và 0 bằng nhau, phải không?
ASCIIThenANSI

1
Chúng tôi có thể có thêm một số dữ liệu thử nghiệm không?
alexander-brett

Câu trả lời:


2

C

Nếu bạn không sử dụng Linux hoặc gặp sự cố biên dịch, có lẽ bạn nên xóa mã thời gian ( 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;
}

Ví dụ trường hợp:

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$ 

(Thời gian dành cho CPU i7-4770K tốc độ 4,1 GHz.) Hãy cẩn thận, testcase-hardsử dụng khoảng 3-4 GB bộ nhớ.

Đây là khá nhiều việc thực hiện blutorange phương pháp loại trừ bao gồm, nhưng được thực hiện để nó sẽ xử lý các giao điểm ở bất kỳ độ sâu nào. Mã như được viết đang dành rất nhiều thời gian cho việc cấp phát bộ nhớ và sẽ còn nhanh hơn nữa khi tôi tối ưu hóa việc quản lý bộ nhớ.

Tôi đã loại bỏ khoảng 25% testcase-hard, nhưng hiệu suất trên bản gốc ( testcase-long) không thay đổi nhiều, vì không có nhiều phân bổ bộ nhớ đang diễn ra ở đó. Tôi sẽ điều chỉnh thêm một chút trước khi tôi gọi nó: Tôi nghĩ rằng tôi có thể có thể cải thiện 25% -50% testcase-long.

Toán học

Khi tôi nhận thấy đây là sự cố #SAT, tôi nhận ra rằng tôi có thể sử dụng tích hợp sẵn của 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]]
]

Đầu ra:

{1.296944, 298208861472}

Đó là 298.208.861.472 mặt nạ trong 1,3 giây (i7-3517U @ 1.9 GHz), bao gồm cả thời gian tải xuống trường hợp thử nghiệm từ pastebin.


Vì vậy, tôi đã viết lại điều này trong C ... thật không may là tôi quá nhanh để sử dụng gperftools trên nó! Tôi sẽ tìm thấy một số trường hợp thử nghiệm khó hơn trước khi tôi đăng vào ngày mai.
2012rcampion

testcase-hardcó thể được hoàn thành rất nhanh nếu mã của bạn tìm kiếm mặt nạ có thể được kết hợp. Nếu mã của bạn thực hiện điều này, sau đó xóa mọi dòng khác (vì vậy chỉ còn các /^2*02*$/trường hợp). Tôi không nghĩ rằng trường hợp đó có thể được tối ưu hóa.
2012rcampion

4

ruby, khá nhanh, nhưng nó phụ thuộc vào đầu vào

Bây giờ tăng tốc theo hệ số 2 ~ 2,5 bằng cách chuyển từ chuỗi sang số nguyên.

Sử dụng:

cat <input> | ruby this.script.rb

Ví dụ.

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

Số lượng các trận đấu cho một mặt nạ duy nhất được tính bằng hệ số nhị thức. Vì vậy, ví dụ 122020cần 3 2s đầy, 1 0và 2 1. Do đó, có nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3các chuỗi nhị phân khác nhau phù hợp với mặt nạ này.

Giao điểm giữa n mặt nạ m_1, m_2, ... m_n là mặt nạ q, sao cho chuỗi nhị phân s khớp với q chỉ khi nó khớp với tất cả các mặt nạ m_i.

Nếu chúng ta lấy hai mặt nạ m_1 và m_2, giao điểm của nó dễ dàng được tính toán. Chỉ cần đặt m_1 [i] = m_2 [i] nếu m_1 [i] == 2. Giao điểm giữa 122020111222111020:

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

Hai mặt nạ riêng lẻ được khớp bởi 3 + 1 = 4 chuỗi, mặt nạ xen kẽ được khớp bởi một chuỗi, do đó có 3 + 1-1 = 3 chuỗi duy nhất khớp với một hoặc cả hai mặt nạ.

Tôi sẽ gọi N (m_1, m_2, ...) số chuỗi khớp với tất cả m_i. Áp dụng logic tương tự như trên, chúng ta có thể tính toán số chuỗi duy nhất khớp với ít nhất một mặt nạ, được đưa ra theo nguyên tắc loại trừ bao gồm và xem bên dưới, như sau:

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

Có rất nhiều, rất nhiều, rất nhiều sự kết hợp của việc dùng, nói 30 mặt nạ trong số 200.

Vì vậy, giải pháp này đưa ra giả định rằng không có nhiều giao điểm bậc cao của mặt nạ đầu vào tồn tại, tức là. hầu hết n-tuples của n> 2 mặt nạ sẽ không có bất kỳ kết quả khớp nào.

Sử dụng mã ở đây, mã tại ideone có thể bị lỗi thời.

Tôi đã thêm một chức năng remove_duplicatescó thể được sử dụng để xử lý trước các mặt nạ đầu vào và xóa m_isao cho tất cả các chuỗi khớp với nó cũng khớp với mặt nạ khác m_j. Đối với đầu vào hiện tại, việc này thực sự mất nhiều thời gian hơn vì không có mặt nạ nào như vậy (hoặc không nhiều) , do đó, hàm không được áp dụng cho dữ liệu trong mã bên dưới.

Mã số:

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

Điều này được gọi là nguyên tắc loại trừ bao gồm, nhưng trước khi ai đó chỉ cho tôi, tôi đã có bằng chứng của riêng mình, vì vậy nó sẽ đi. Làm một cái gì đó bản thân bạn cảm thấy tuyệt vời mặc dù.

Hãy để chúng tôi xem xét trường hợp của 2 mặt nạ, gọi sau đó 01, đầu tiên. Chúng tôi lấy mọi chuỗi nhị phân cân bằng và phân loại nó theo mặt nạ mà nó khớp. c0là số lượng những người chỉ phù hợp với mặt nạ 0, c1nữ tu sĩ của những người chỉ phù hợp với 1, c01những người phù hợp với mặt nạ 01.

Gọi s0là tổng số của số lượng khớp cho mỗi mặt nạ (chúng có thể trùng nhau). Gọi s1là tổng số lượng trận đấu cho mỗi cặp (2 kết hợp) mặt nạ. Gọi s_ilà tổng số lượng các trận đấu cho mỗi kết hợp (i + 1) của mặt nạ. Số lượng kết hợp của mặt nạ n là số chuỗi nhị phân khớp với tất cả các mặt nạ.

Nếu có n mặt nạ, đầu ra mong muốn là tổng của tất cả c, nghĩa là. c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). Những gì chương trình tính toán là tổng xen kẽ của tất cả s, tức là. s = s_0-s_1+s_2-+...+-s_(n-1). Chúng tôi muốn chứng minh điều đó s==c.

n = 1 là hiển nhiên. Xét n = 2. Đếm tất cả các trận đấu của mặt nạ 0cho c0+c01(số lượng chuỗi phù hợp với chỉ 0 + những hợp cả hai 01), đếm tất cả các trận đấu của 1cho c1+c02. Chúng ta có thể minh họa điều này như sau:

0: c0 c01
1: c1 c10

Theo định nghĩa , s0 = c0 + c1 + c12. s1là tổng số trận đấu của mỗi kết hợp 2 [0,1], nghĩa là. tất cả uniqye c_ijs. Hãy ghi nhớ điều đó c01=c10.

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

Do đó s=cvới n = 2.

Bây giờ hãy xem xét 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

Do đó s=cvới n = 3. c__iđại diện cho tất cả các cs với (i + 1) chỉ số, ví dụ c__1 = c01cho n = 2 và c__1 = c01 + c02 + c12cho n == 3.

Với n = 4, một mẫu bắt đầu xuất hiện:

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

Do đó s==cvới n = 4.

Nói chung, chúng tôi nhận được các hệ số nhị thức như thế này (là i, → là 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  .  .  . 
.                       .
.                          .
.                             .

Để thấy điều này, hãy xem xét điều đó đối với một số ij, có:

  • x = ncr (n, i + 1): kết hợp C cho giao điểm của (i + 1) mặt nạ ngoài n
  • y = ncr (ni-1, ji): với mỗi kết hợp C ở trên, có y kết hợp khác nhau cho giao điểm của (j + 2) trong số các kết hợp có chứa C
  • z = ncr (n, j + 1): các kết hợp khác nhau cho giao điểm của (j + 1) mặt nạ ngoài n

Vì điều đó nghe có vẻ khó hiểu, đây là định nghĩa được áp dụng cho một ví dụ. Với i = 1, j = 2, n = 4, nó trông như thế này (xem ở trên):

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

Vì vậy, ở đây x = 6 (01, 02, 03, 12, 13, 23), y = 2 (hai c với ba chỉ số cho mỗi kết hợp), z = 4 (c012, c013, c023, c123).

Tổng cộng, có các x*yhệ số cvới (j + 1) chỉ số và có các hệ số zkhác nhau, do đó, mỗi x*y/zlần xảy ra , chúng tôi gọi là hệ số k_ij. Bằng đại số đơn giản, chúng tôi nhận được k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).

Vì vậy, chỉ số được đưa ra bởi k_ij = nCr(j+1,i+1)Nếu bạn nhớ lại tất cả các khuyết điểm, tất cả những gì chúng ta cần chỉ ra là tổng số xen kẽ của mỗi cột cho 1.

s0 - s1 + s2 - s3 +- ... +- s(n-1)Do đó, tổng xen kẽ có thể được biểu thị như sau:

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

Do đó s=cvới mọi n = 1,2,3, ...


1
Tôi không chắc là bạn có biết hay không, nhưng phương pháp bạn đang áp dụng là en.wikipedia.org/wiki/Ininating%E2%80%93exinating_principl , vì vậy bạn không phải chứng minh điều đó, nếu đây là điều bạn đang cố gắng làm Ngoài ra, trong khi không cần thiết cho các trường hợp thử nghiệm, bạn có thể loại bỏ khỏi các mặt nạ nhóm hoàn toàn được bao gồm trong một mặt nạ khác trong nhóm. Ví dụ trong TC5: 0011 < 2211, 0022 < 0222. Tôi nghĩ rằng điều này làm cho các nhóm không lớn hơn 2*n, mặc dù nó vẫn quá lớn trong trường hợp xấu nhất.
nutki

@nutki Tôi đã không nhận thức được điều này, vì vậy cảm ơn vì liên kết. Thỉnh thoảng, chứng minh và suy nghĩ về một cái gì đó cho bản thân vẫn là một bài tập tốt, mặc dù :). Đối với đề xuất của bạn, vâng, điều đó đã xảy ra với tôi để làm điều đó, nhưng tôi không nghĩ rằng tôi sẽ thực hiện nó trừ khi một trường hợp thử nghiệm được thêm vào đòi hỏi nó phải có kết quả trong một khoảng thời gian hợp lý.
blutorange

@blutorange bạn có nghĩ dùng cây quyết định không?
Abr001am

Tôi nghĩ bạn có nghĩa là giao điểm (khớp cả hai mặt nạ), không phải liên kết (khớp với mặt nạ này hoặc mặt nạ kia).
2012rcampion 15/05/2015

@ 2012rcampion Như trong unifying two masksthuật ngữ unioncó ý nghĩa với tôi và tôi xan định nghĩa theo cách đó, nhưng bạn nói đúng, vì lợi ích của sự hiểu biết lẫn nhau mà tôi đã nói. @ Agawa001 Bạn có thể cụ thể hơn? Ngoài ra, nếu bạn có một số ý tưởng hay để thực hiện việc này nhanh hơn, hãy sử dụng bất kỳ ý tưởng nào từ câu trả lời này cho chương trình / câu trả lời của bạn. Hiện tại, nó đủ nhanh cho trường hợp thử nghiệm lớn và nếu được thực hiện đa luồng thì phải mất <0,1s, thấp hơn bất kỳ phép đo / so sánh có ý nghĩa nào, vì vậy đối với các trường hợp thử nghiệm khó hơn là cần thiết.
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]);
    }
}

Chúc may mắn nhận được đầu vào lớn để chạy trên này - có lẽ sẽ mất cả đêm để vượt qua khoảng. 60 ^ 30 hoán vị! Có lẽ một tập dữ liệu kích thước trung gian có thể là một ý tưởng tốt?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.