นับจำนวนสตริงไบนารีที่สมดุลที่ตรงกับชุดของมาสก์


10

สตริงไบนารีคือสตริงที่มีตัวละครเท่านั้นที่มาจาก01 สตริงไบนารีสมดุลเป็นสตริงไบนารีซึ่งมีเป็นจำนวนมากว่า0ในฐานะ1 s

คุณจะได้รับจำนวนเต็มบวกnและจำนวนมาสก์โดยพลการแต่ละตัวมีความยาว2nอักขระและมีอักขระที่ดึงออกมาจาก012เท่านั้น สตริงไบนารีและการแข่งขันหน้ากากถ้ามันเป็นระยะเวลาเดียวกันและตกลงที่ตัวอักษรในทุกตำแหน่งที่หน้ากากไม่ได้2 เช่นหน้ากาก011022ตรงกับสตริงไบนารี011000 , 011001 , 011010 , 011011

รับnและมาสก์เป็นอินพุต (คั่นด้วยบรรทัดใหม่) คุณต้องส่งออกจำนวนสตริงไบนารีที่สมดุลที่แตกต่างกันซึ่งตรงกับมาสก์หนึ่งตัวหรือมากกว่า

ตัวอย่าง

อินพุต

3
111222
000112
122020
122210
102120

เหตุผล

  • สมดุลเพียงไบนารีการจับคู่สาย111,222เป็น111,000
  • สมดุลเพียงไบนารีการจับคู่สาย000112เป็น000111
  • สมดุลสตริงไบนารีที่ตรงกับ122,020เป็น111,000 (นับแล้ว), 110010และ101010
  • สมดุลสตริงไบนารีที่ตรงกับ122,210เป็น110,010 (นับแล้ว) 101,010 (นับแล้ว) และ100110
  • สมดุลสตริงไบนารีที่ตรงกับ102,120เป็น101,100และ100,110 (นับแล้ว)

ดังนั้นผลลัพธ์ควรเป็น

6

อินพุต

10
22222222222222222222

เหตุผล

  • มี20 ให้เลือก 10สตริงไบนารีแบบสมดุลของความยาว 20

เอาท์พุต

184756

ผู้ชนะ

ผู้ชนะจะเป็นผู้คำนวณการแข่งขันให้เร็วที่สุดและแน่นอนว่าจะปฏิบัติเช่นเดียวกับการใส่ข้อมูลอื่น ๆ (ฉันใช้รหัสที่กำหนดเพื่อให้ได้ผู้ชนะที่ชัดเจนและหลีกเลี่ยงกรณีที่อินพุตที่แตกต่างกันจะให้ผู้ชนะที่แตกต่างกันถ้าคุณคิดว่าวิธีที่ดีกว่าในการค้นหารหัสที่เร็วที่สุดบอกฉันได้)

อินพุตการแข่งขัน

http://pastebin.com/2Dg7gbfV


2
นอกจากนี้ฉันเองชอบgist.github.comมากกว่า pastebin ทั้งเพื่อความสวยงามและความผิดพลาดในอนาคต
orlp

3
@AlbertMasclans ฉันคิดว่าคุณควรสงวนสิทธิ์ในการเปลี่ยนอินพุต มิฉะนั้นคนสามารถ hardcode เอาท์พุท
mbomb007

1
มันจะมีประโยชน์ถ้าคุณสามารถโพสต์ตัวอย่างเล็ก ๆ ในคำถามพร้อมกับผลลัพธ์ที่คาดหวังและคำอธิบาย ฉันอาจจะช้า แต่ฉันไม่ได้รับความหมายค่อนข้าง ตัวอย่างเช่นตั้งแต่ n = 30 เรากำลังมองหาลำดับของ 30 0s หรือ 30 1s (โดยที่ 2 เป็นสัญลักษณ์แทน) ในแถวใดแถวหนึ่ง? ลำดับเหล่านั้นทับซ้อนกันได้หรือไม่ ตัวอย่างเช่นหากฉันพบลำดับ 32 1s จะนับเป็น 3 ลำดับหรือเป็นลำดับเดียวหรือไม่ ถ้าฉันพบลำดับ 60 1s (ทั้งแถว) จะเป็นอย่างไร นั่นคือ 1 ลำดับ 2 ลำดับหรือ 31 ลำดับ?
Reto Koradi

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$ 

(เวลาสำหรับซีพียู i7-4770K ที่ 4.1 GHz.) ระวังtestcase-hardใช้หน่วยความจำประมาณ 3-4 GB

นี่เป็นการดำเนินการตามวิธีการแยกส่วนที่แยกออกจากกัน แต่ทำเพื่อที่จะจัดการจุดตัดของความลึกใด ๆ รหัสตามที่เขียนใช้เวลาในการจัดสรรหน่วยความจำมากและจะเร็วขึ้นเมื่อฉันเพิ่มประสิทธิภาพการจัดการหน่วยความจำ

ฉันลดราคาลงประมาณ 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}

นั่นคือ 298,208,861,472 มาสก์ใน 1.3 วินาที (i7-3517U @ 1.9 GHz) รวมถึงเวลาที่ใช้ในการดาวน์โหลดกรณีทดสอบจาก pastebin


ดังนั้นฉันจึงเขียนมันใหม่ใน 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

จำนวนการจับคู่สำหรับหน้ากากเดียวที่คำนวณได้โดยสัมประสิทธิ์ทวินาม ดังนั้นสำหรับตัวอย่างเช่น122020ต้องการ 3 2s ที่เต็มไปด้วย 1 0และ 12 ดังนั้นจึงมีnCr(3,2)=nCr(3,1)=3!/(2!*1!)=3สตริงไบนารีที่แตกต่างกันตรงกับหน้ากากนี้

ทางแยกระหว่าง n มาสก์ m_1, m_2, ... m_n เป็นมาสก์ q ซึ่งเป็นสตริงไบนารี s จับคู่ q เฉพาะถ้ามันตรงกับมาสก์ทั้งหมด m_i

หากเราใช้สองมาสก์ m_1 และ m_2 จุดตัดของมันจะถูกคำนวณอย่างง่ายดาย เพียงตั้งค่า m_1 [i] = m_2 [i] ถ้า m_1 [i] == 2 จุดตัดระหว่าง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 สตริงมาสก์ interesection จับคู่กับหนึ่งสายดังนั้นจึงมี 3 + 1-1 = 3 สายที่ไม่ซ้ำกันที่ตรงกับหนึ่งหรือทั้งสองมาสก์

ฉันจะโทรหา N (m_1, m_2, ... ) จำนวนสตริงที่ตรงกับ m_i ทั้งหมด การใช้ตรรกะเดียวกันกับข้างต้นเราสามารถคำนวณจำนวนของสตริงที่ไม่ซ้ำกันซึ่งจับคู่กับหน้ากากอย่างน้อยหนึ่งตัวที่กำหนดโดยหลักการการแยกแบบรวมและดูด้านล่างเช่นกัน:

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

มีหลายอย่างหลายอย่างรวมกันหลายอย่างพูด 30 หน้ากากจาก 200

ดังนั้นวิธีการแก้ปัญหานี้ทำให้ข้อสันนิษฐานว่ามีมาสก์อินพุทสูงมากที่มีอยู่ไม่มากเช่น n-tuples ส่วนใหญ่ของมาสก์ n> 2 จะไม่มีการจับคู่ทั่วไป

ใช้รหัสที่นี่รหัสที่ ideone อาจล้าสมัย

ฉันได้เพิ่มฟังก์ชั่น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, c1nunber ของผู้ที่ตรงกับเพียง1, c01ผู้ที่หน้ากากแข่งขันและ01

อนุญาตs0เป็นจำนวนรวมของจำนวนการแข่งขันสำหรับหน้ากากแต่ละอัน (พวกเขาอาจทับซ้อนกัน) อนุญาตs1เป็นผลรวมของจำนวนการแข่งขันสำหรับแต่ละคู่ (รวมกัน 2 คู่) ของมาสก์ อนุญาตs_iเป็นผลรวมของจำนวนการแข่งขันสำหรับการรวมกันของ (i + 1) ของมาสก์ จำนวนการจับคู่ของ n-mask คือจำนวนของสตริงไบนารีที่ตรงกับมาสก์ทั้งหมด

หากมีมาสก์ 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 + จับคู่เหล่านั้นทั้งใน0และ1) นับการแข่งขันทั้งหมดของให้1 c1+c02เราสามารถอธิบายสิ่งนี้ได้ดังนี้:

0: c0 c01
1: c1 c10

ตามคำนิยาม, s0 = c0 + c1 + c12. s1คือจำนวนรวมของการแข่งขันของการรวมกันของ[0,1]2 รายการ ทั้งหมด uniqye c_ijs c01=c10เก็บไว้ในใจว่า

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

ดังนั้นs=cสำหรับ n = 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=cสำหรับ n = 3 c__iแสดงถึงของทั้งหมดcที่มี (i + 1) ดัชนีเช่นc__1 = c01สำหรับ n = 2 และc__1 = c01 + c02 + c12สำหรับ n == 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==cสำหรับ n = 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): ชุดค่าผสม C สำหรับจุดตัดของ (i + 1) ปิดบัง n
  • y = ncr (ni-1, ji): สำหรับชุดค่าผสมแต่ละ C ด้านบนมีชุดค่าผสม y ที่แตกต่างกันสำหรับการแยกของมาสก์ (j + 2) ออกจากชุดที่มี C
  • z = ncr (n, j + 1): ชุดค่าผสมที่แตกต่างกันสำหรับจุดตัดของ (j + 1) มาสก์ออกจาก n

เนื่องจากอาจทำให้เกิดความสับสนนี่คือข้อ จำกัด ที่ใช้กับตัวอย่าง สำหรับ i = 1, j = 2, n = 4, มันมีลักษณะเช่นนี้ (cf. ด้านบน):

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 (สองคมีสามดัชนีสำหรับแต่ละชุด), z = 4 (c012, c013, c023, c123)

โดยรวมแล้วมีx*yค่าสัมประสิทธิ์cกับ (ญ + 1) ดัชนีและมีzคนที่แตกต่างกันเพื่อให้แต่ละเกิดขึ้นครั้งซึ่งเราเรียกว่าค่าสัมประสิทธิ์x*y/z โดยพีชคณิตง่ายที่เราได้รับk_ijk_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เหมาะสมกับฉันและฉัน xan กำหนดวิธีการที่ แต่คุณถูกต้องในความสนใจของความเข้าใจซึ่งฉันได้ chabged @ Agawa001 คุณมีความเจาะจงมากกว่านี้ไหม? นอกจากนี้หากคุณมีความคิดที่ดีในการทำให้เร็วขึ้นอย่าลังเลที่จะใช้ความคิดใด ๆ จากคำตอบนี้สำหรับโปรแกรม / คำตอบของคุณ สำหรับตอนนี้มันเร็วพอสำหรับกรณีทดสอบขนาดใหญ่และหากทำแบบมัลติเธรดควรใช้เวลา <0.1 วินาทีซึ่งต่ำกว่าการวัด / การเปรียบเทียบที่มีความหมายใด ๆ ดังนั้นจึงจำเป็นสำหรับกรณีทดสอบที่หนักกว่า
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.