마스크 세트 중 하나와 일치하는 균형 잡힌 이진 문자열 수


10

바이너리 문자열 에서 가져온 문자 만 포함하는 문자열입니다 01 . 균형 이진 문자열은 정확하게 많은 등이 포함 된 바이너리 문자열 0 으로들 1 개 의.

양의 정수 n 과 임의의 수의 마스크가 제공되는데, 각 마스크의 길이 는 2n 자이며 012 에서 그린 문자 만 포함합니다 . 이진 문자열과 마스크는 길이가 같고 마스크에 2 가없는 모든 위치의 문자에 일치하면 일치합니다 . 예를 들어, 마스크 011022 는 이진 문자열 011000 , 011001 , 011010 , 011011 과 일치합니다 .

주어 N 과 (개행 문자에 의해 분리) 입력으로서 마스크하면 출력해야 더 마스크 중 하나와 일치하거나 별개의 균형 이진 스트링 수.

입력

3
111222
000112
122020
122210
102120

추리

  • 111222 와 일치하는 유일한 균형 이진 문자열 은 111000 입니다.
  • 일치하는 유일한 균형 이진 문자열 000,112이 있다 000111 .
  • 122020 과 일치하는 균형 이진 문자열 은 111000 (이미 계산 됨), 110010101010 입니다.
  • 122210 과 일치하는 균형 이진 문자열 은 110010 (이미 계산 됨), 101010 (이미 계산 됨) 및 100110 입니다.
  • 102120 과 일치하는 균형 이진 문자열 은 101100100110입니다 (이미 계산 됨).

따라서 출력은

6

입력

10
22222222222222222222

추리

  • 있다 (20)가 10 선택 의 길이 (20)의 균형 잡힌 이진 문자열을.

산출

184756

우승자

승자는 경쟁 입력을 가장 빠르게 계산하는 사람이 될 것이며 물론 다른 입력과 같은 방식으로 처리합니다. (확실한 승자를 확보하기 위해 결정된 코드를 사용하고 다른 입력으로 인해 다른 승자가 제공되는 경우를 피합니다. 가장 빠른 코드를 찾는 더 좋은 방법을 생각하면 알려주세요).

경쟁 입력

http://pastebin.com/2Dg7gbfV


2
또한 개인적 으로 미학과 미래의 결함 모두에 대해 gist.github.com 을 pastebin보다 선호합니다 .
orlp

3
@AlbertMasclans 나는 당신이 입력을 변경할 권리를 보유해야한다고 생각합니다. 그렇지 않으면 누군가 출력을 하드 코딩 할 수 있습니다.
mbomb007

1
예상 결과와 설명이 포함 된 작은 예제를 질문에 게시 할 수 있다면 유용 할 것입니다. 나는 느리지 만 정의를 얻지 못합니다. 예를 들어, n = 30 이후, 어떤 행에서 30 0 또는 30 1 (2는 와일드 카드)의 시퀀스를 찾고 있습니까? 이러한 시퀀스가 ​​겹칠 수 있습니까? 예를 들어 32 1의 시퀀스를 찾으면 3 시퀀스 또는 단일 시퀀스로 계산됩니까? 60 1의 시퀀스 (전체 행)를 찾으면 어떻게합니까? 1 열, 2 열 또는 31 열입니까?
Reto Koradi 3:14에

3
따라서이 행렬에서 1과 0의 수를 갖는 고유 한 배열의 수를 요구하고 있습니까?
ASCIIThenANSI

1
테스트 데이터 좀 더 주 시겠어요?
alexander-brett

답변:


2

Linux를 사용하지 않거나 컴파일하는 데 문제가 있으면 타이밍 코드 ( 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;
}

사례 예 :

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$ 

(4.1GHz의 i7-4770K CPU 시간입니다.) testcase-hard약 3-4GB의 메모리를 사용 하십시오 .

이것은 blutorange가 내포 한 배타적 배제 방법의 구현과 거의 비슷하지만 어떤 깊이의 교차점도 처리 할 수 ​​있습니다. 작성된 코드는 메모리 할당에 많은 시간을 소비하며 메모리 관리를 최적화하면 더 빨라집니다.

나는 약 25 %를 깎았 testcase-hard지만 testcase-long메모리 할당이 많지 않기 때문에 원본 ( ) 의 성능 은 거의 변하지 않았습니다. 전화하기 전에 조금 더 조정하겠습니다. 25 % -50 % 향상 될 수도 있습니다 testcase-long.

매스 매 티카

이것이 #SAT 문제라는 것을 알게되자 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]]
]

산출:

{1.296944, 298208861472}

이는 페이스트 빈에서 테스트 케이스를 다운로드하는 데 걸린 시간을 포함하여 1.3 초 (i7-3517U @ 1.9GHz)로 298,208,861,472 개의 마스크입니다.


그래서 나는 이것을 C로 다시 작성했습니다 ... 불행히도 gperftools를 사용하기에는 너무 빠릅니다! 내일 게시하기 전에 좀 더 어려운 테스트 사례를 찾을 수 있습니다.
2012rcampion

testcase-hard코드에서 결합 할 수있는 마스크를 찾으면 매우 빠르게 완료 될 수 있습니다. 코드 에서이 작업을 수행하면 다른 모든 줄을 삭제하십시오 (따라서 /^2*02*$/사례 만 남습니다). 나는 그 사건이 최적화 될 수 없다고 생각합니다.
2012rcampion

4

루비, 꽤 빠르지 만 입력에 따라 다릅니다.

이제 문자열에서 정수로 전환하여 2 ~ 2.5 배 속도를 높입니다.

용법:

cat <input> | ruby this.script.rb

예 :

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

이항 계수로 쉽게 계산되는 단일 마스크의 일치 횟수입니다. 예를 들어 채워진 1220203 과 21 0과 2가 필요 1합니다. 따라서이 nCr(3,2)=nCr(3,1)=3!/(2!*1!)=3마스크와 일치하는 다른 이진 문자열이 있습니다.

n 마스크 m_1, m_2, ... m_n 사이의 교차점은 마스크 q이므로 이진 문자열 s는 모든 마스크 m_i와 일치하는 경우에만 q와 일치합니다.

두 개의 마스크 m_1과 m_2를 가져 오면 그 교차점을 쉽게 계산할 수 있습니다. m_1 [i] == 2 인 경우 m_1 [i] = m_2 [i]를 설정하십시오. 사이의 교차 122020하고 111222있습니다 111020:

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

두 개의 개별 마스크는 3 + 1 = 4 개의 문자열과 일치하고 교차 마스크는 하나의 문자열과 일치하므로 하나 또는 두 개의 마스크와 일치하는 3 + 1-1 = 3 개의 고유 한 문자열이 있습니다.

모든 m_i와 일치하는 문자열 수를 N (m_1, m_2, ...)이라고합니다. 위와 동일한 논리를 적용하여 포함 제외 원칙 에 따라 하나 이상의 마스크와 일치하는 고유 문자열의 수를 계산하고 다음과 같이 확인할 수 있습니다.

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 개의 마스크 중 30 개의 마스크를 취하는 많은 조합이 있습니다.

따라서이 솔루션은 입력 마스크의 고차 교점이 많지 않다는 가정을합니다. n> 2 마스크의 대부분의 n- 튜플에는 공통 일치 항목이 없습니다.

여기 코드를 사용하십시오. 아이디어 코드가 오래되었을 수 있습니다.

remove_duplicates입력을 사전 처리하고 마스크를 삭제 m_i하여 일치하는 모든 문자열이 다른 마스크와 일치 하도록 사용할 수 있는 기능 을 추가했습니다 m_j. 현재 입력의 경우 실제로 해당 마스크가 없기 때문에 시간이 오래 걸립니다. 함수는 아직 아래 코드에서 데이터에 적용되지 않습니다.

암호:

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

이것을 포함 배제 원칙이라고합니다. 그러나 누군가가 그것을 지적하기 전에 나는 내 자신의 증거를 얻었습니다. 그래도 스스로 무언가를하는 것은 기분이 좋습니다.

다음 호출, 우리가 2 마스크의 경우를 생각해 보자 0하고 1처음. 모든 균형 이진 문자열을 가져 와서 일치하는 마스크에 따라 분류합니다. c0마스크 만 일치하는 항목의 수 0, c1단지 일치하는 사람들의 nunber 1, c01그 일치하는 마스크 0와는 1.

하자 s0각 마스크 일치의 숫자의 개수 합 (들은 중첩 될 수있다). 하자 s1마스크의 각 쌍 (2 조합)에 대한 일치하는 수의 합. LET s_i마스크들 각각은 (i + 1)의 조합에 대한 일치의 수의 합. n- 마스크의 일치 수는 모든 마스크와 일치하는 이진 문자열의 수입니다.

n 개의 마스크가 있다면, 원하는 출력은 모든의 합 c, 즉 c = c0+...+cn+c01+c02+...+c(n-2)(n-1)+c012+...+c(n-3)(n-2)(n-1)+...+c0123...(n-2)(n-1). 프로그램이 계산하는 것은 모든 것의 교호 합입니다 s. s = s_0-s_1+s_2-+...+-s_(n-1). 우리는 그것을 증명하고 싶습니다 s==c.

n = 1은 분명하다. n = 2를 고려하십시오. 마스크 모두 일치 계산하여 0준다 c0+c01(단 0 + 해당 정합 모두 일치하는 문자열의 개수 01의 모든 매치 카운트) 1제공을 c1+c02. 이를 다음과 같이 설명 할 수 있습니다.

0: c0 c01
1: c1 c10

정의에 따라 s0 = c0 + c1 + c12. s1는의 각 2 조합의 일치하는 합계 수입니다 [0,1]. 모든 uniqye는 c_ij이야. 명심하십시오 c01=c10.

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

따라서 s=cn은 2이다.

이제 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

따라서 s=cn = 3이다. c__ic(i + 1) 지수를 갖는 모든 s의, 예 c__1 = c01를 들어 n = 2 및 c__1 = c01 + c02 + c12n == 3을 나타낸다.

n = 4의 경우 패턴이 나타납니다.

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

따라서 s==cn = 4의 경우.

일반적으로 다음과 같은 이항 계수를 얻습니다 (↓는 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  .  .  . 
.                       .
.                          .
.                             .

이를 확인하려면 몇 가지에 대한 것을 고려 i하고 j있다 :

  • x = ncr (n, i + 1) : n에서 (i + 1) 마스크의 교집합에 대한 조합 C
  • y = ncr (ni-1, ji) : 위의 각 조합 C에 대해 C를 포함하는 마스크와 (j + 2) 마스크의 교차점에 대해 서로 다른 조합이 있습니다.
  • z = ncr (n, j + 1) : n에서 (j + 1) 마스크의 교차점에 대한 다른 조합

혼란스럽게 들릴 수 있으므로 여기에 정의가 적용됩니다. i = 1, j = 2, n = 4의 경우 다음과 같습니다 (위 참조).

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

따라서 여기서 x = 6 (01, 02, 03, 12, 13, 23), y = 2 (각 조합에 대해 세 개의 인덱스가있는 두 개의 c), z = 4 (c012, c013, c023, c123)입니다.

전체적으로, (j + 1) 지수를 가진 x*y계수 cz있고, 다른 지수 가 있으므로, 각각 발생하는 x*y/z시간을 계수라고합니다 k_ij. 간단한 대수로 우리는를 얻습니다 k_ij = ncr(n,i+1) ncr(n-i-1,j-i) / ncr(n,j+1) = ncr(j+1,i+1).

따라서 k_ij = nCr(j+1,i+1)모든 정의를 기억하면 각 열의 교호 합이 1을 얻는 것만으로도 충분합니다.

따라서 교류 합계 s0 - s1 + s2 - s3 +- ... +- s(n-1)는 다음과 같이 표현 될 수 있습니다.

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

따라서 s=c모든 n = 1,2,3, ...


1
당신이 알고 있는지 확실하지 않지만 적용하는 방법은 en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle입니다 . 하다. 또한 테스트 사례에는 필요하지 않지만 그룹의 다른 마스크에 완전히 포함 된 그룹 마스크를 제거 할 수 있습니다. 예를 들어 TC5 : 0011 < 2211, 0022 < 0222. 나는 이것이 2*n최악의 경우에는 여전히 너무 크지 만 이것이 그룹을 더 크게 만들지 않는다고 생각합니다 .
nutki

@nutki 나는 이것을 알지 못 했으므로 링크에 감사드립니다. 때로는 자신을 위해 무언가를 증명하고 생각하는 것이 여전히 좋은 운동입니다. 당신의 제안에 관해서는, 그렇습니다. 그렇습니다. 그러나 합리적인 시간 내에 결과를 얻는 데 필요한 테스트 케이스가 추가되지 않으면 구현할 것이라고 생각하지 않습니다.
blutorange

@blutorange 의사 결정 트리를 사용하려고 생각 했습니까?
Abr001am

난 당신이 평균 생각 교차로 (모두 마스크를 일치)이 아닌 노동 조합이 (하나 또는 다른 마스크와 일치).
2012rcampion

@ 2012rcampion unifying two masks용어 union가 나에게 의미가 있고 나는 그런 식으로 정의하지만, 당신은 내가 이해 한 상호 이해에 관심이 있습니다. @ Agawa001 더 구체적으로 할 수 있습니까? 또한 더 빠른 아이디어를 얻으려면이 답변의 아이디어를 프로그램 / 답변에 자유롭게 사용하십시오. 현재로서는 큰 테스트 사례에 대해 충분히 빠르며 멀티 스레드로 만든 경우 <0.1s가 필요합니다. 이는 의미있는 측정 / 비교 아래에 있으므로 더 어려운 테스트 사례가 필요합니다.
blutorange

1

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

큰 입력을 얻으려면 행운을 빕니다. 약 밤새도록 밤이 걸릴 것입니다. 60 ^ 30 순열! 아마도 중간 크기의 데이터 세트가 좋은 생각일까요?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.