Tìm ma trận điểm cao nhất không có thuộc tính X


14

Thử thách này một phần là thử thách thuật toán, một phần là thử thách tối ưu hóa và một phần đơn giản là thử thách mã nhanh nhất.

Một ma trận tuần hoàn được chỉ định đầy đủ bởi hàng đầu tiên của nó r. Các hàng còn lại là mỗi hoán vị theo chu kỳ của hàng rvới độ lệch bằng với chỉ số hàng. Chúng tôi sẽ cho phép các ma trận tuần hoàn không vuông để chúng đơn giản là thiếu một số hàng cuối cùng của chúng. Tuy nhiên, chúng tôi luôn cho rằng số lượng hàng không nhiều hơn số lượng cột. Ví dụ, hãy xem xét ma trận 3 theo 5 chu kỳ sau đây.

10111
11011
11101

Chúng ta nói một ma trận có thuộc tính X nếu nó chứa hai tập hợp cột không trống với các chỉ số không giống nhau có cùng tổng (vectơ). Tổng vectơ của hai cột chỉ đơn giản là tổng của phần tử của hai cột. Đó là tổng của hai cột chứa xcác phần tử, mỗi cột là một cột khác chứa xcác phần tử.

Ma trận trên tầm thường có thuộc tính X là cột đầu tiên và cột cuối cùng giống nhau. Ma trận danh tính không bao giờ có thuộc tính X.

Nếu chúng ta chỉ xóa cột cuối cùng của ma trận ở trên thì chúng ta sẽ lấy một ví dụ không có thuộc tính X và sẽ cho điểm 4/3.

1011
1101
1110

Nhiệm vụ

Nhiệm vụ là viết mã để tìm ma trận tuần hoàn có điểm cao nhất có các mục nhập đều là 0 hoặc 1 và không có thuộc tính X.

Ghi bàn

Điểm của bạn sẽ là các cột số chia cho số lượng hàng trong ma trận chấm điểm tốt nhất của bạn.

Tie Breaker

Nếu hai câu trả lời có cùng số điểm, câu trả lời đầu tiên sẽ thắng.

Trong trường hợp (rất) không chắc là ai đó tìm được phương pháp để đạt điểm không giới hạn, bằng chứng hợp lệ đầu tiên về giải pháp đó sẽ được chấp nhận. Trong trường hợp thậm chí không chắc chắn hơn là bạn có thể tìm thấy một bằng chứng về sự tối ưu của một ma trận hữu hạn, tất nhiên tôi cũng sẽ trao giải cho chiến thắng.

Dấu

Đạt được điểm 12/8 không quá khó.

Ngôn ngữ và thư viện

Bạn có thể sử dụng bất kỳ ngôn ngữ nào có trình biên dịch / trình thông dịch / có sẵn miễn phí. cho Linux và bất kỳ thư viện nào cũng có sẵn miễn phí cho Linux.

Mục hàng đầu

  • 36/19 của Peter Taylor (Java)
  • 32/17 bởi Suboptimus Prime (C #)
  • 21/12 bởi justhalf (Python 2)

Ah, thuộc tính X nằm trên cột, không phải hàng.
Tối ưu hóa

Như đã viết, ma trận 1 by 2 01 có thuộc tính X vì tập hợp cột đầu tiên có tổng vectơ giống như tập rỗng. Có lẽ bạn có nghĩa là bộ cột không trống? Tôi nghĩ rằng nó sạch hơn để không thay đổi nó mặc dù.
xnor

2
Cách đọc quy tắc đơn giản nhất vẫn là thuộc 01tính X : (1) = (0) + (1). Nếu bạn muốn loại trừ điều đó thì bạn nên nói rằng hai bộ cột phải rời rạc.
Peter Taylor

1
Câu hỏi này sẽ cung cấp nhiều thông tin chuyên sâu về vấn đề này (về việc kiểm tra thuộc tính X khó đến mức nào, thật không may) mathoverflow.net/questions/157634/ Lỗi
justhalf 6/11/2016

3
Hiện tại chúng tôi chỉ đang cưỡng bức tất cả các 2^mkết hợp cột để kiểm tra thuộc tính X. Nếu chúng tôi có thể bằng cách nào đó nghĩ ra sơ đồ "gặp ở giữa" (xem vấn đề "tổng tập hợp con"), điều này có thể có thể giảm điều đó xuống m * 2^(m/2)...
kennytm

Câu trả lời:


11

16/9 20/11 22/12 28/15 30/16 32/17 34/18 36/19 (Java)

Điều này sử dụng một số ý tưởng để giảm không gian tìm kiếm và chi phí. Xem lịch sử sửa đổi để biết thêm chi tiết về các phiên bản trước của mã.

  • Rõ ràng là wlog chúng ta chỉ có thể xem xét các ma trận tuần hoàn trong đó hàng đầu tiên là một từ Lyndon : nếu từ đó không phải là số nguyên tố thì nó phải có thuộc tính X và nếu không chúng ta có thể xoay mà không ảnh hưởng đến điểm số hoặc thuộc tính X.
  • Dựa trên các phỏng đoán từ những người chiến thắng ngắn được quan sát, giờ đây tôi đang lặp lại qua các từ Lyndon bắt đầu từ những từ có mật độ 50% (nghĩa là cùng số lượng 01) và làm việc; Tôi sử dụng thuật toán được mô tả trong mã A Grey cho các chuỗi vòng có mật độ cố định và các từ Lyndon trong thời gian khấu hao không đổi , Sawada và Williams, Khoa học máy tính lý thuyết 502 (2013): 46-54.
  • Một quan sát thực nghiệm là các giá trị xảy ra theo cặp: mỗi từ Lyndon tối ưu mà tôi thấy có điểm giống như sự đảo ngược của nó. Vì vậy, tôi nhận được về một yếu tố của hai lần tăng tốc bằng cách chỉ xem xét một nửa của mỗi cặp như vậy.
  • Mã ban đầu của tôi đã làm việc với BigIntegerđể đưa ra một thử nghiệm chính xác. Tôi có được một sự cải thiện đáng kể về tốc độ, có nguy cơ âm tính giả, bằng cách vận hành modulo một số nguyên tố lớn và giữ mọi thứ trong nguyên thủy. Số nguyên tố tôi đã chọn là số lớn nhất nhỏ hơn 2 57 , vì nó cho phép nhân với cơ sở của biểu diễn vectơ nổi tiếng của tôi mà không bị tràn.
  • Tôi đã đánh cắp heuristic của Suboptimus Prime rằng có thể nhận được sự từ chối nhanh chóng bằng cách xem xét các tập hợp con theo thứ tự tăng kích thước. Bây giờ tôi đã hợp nhất ý tưởng đó với phương pháp gặp gỡ giữa các tập hợp con thứ ba để kiểm tra các tập hợp con. (Tín dụng cho KennyTM vì đã đề xuất cố gắng điều chỉnh cách tiếp cận từ bài toán tập hợp số nguyên; tôi nghĩ rằng xnor và tôi đã thấy cách để thực hiện đồng thời khá nhiều). Thay vì tìm kiếm hai tập hợp con có thể bao gồm mỗi cột 0 hoặc 1 lần và có cùng một tổng, chúng tôi tìm một tập hợp con có thể bao gồm mỗi cột -1, 0 hoặc 1 lần và tổng bằng 0. Điều này làm giảm đáng kể các yêu cầu bộ nhớ.
  • Có thêm một yếu tố tiết kiệm hai yêu cầu bộ nhớ bằng cách quan sát rằng vì mỗi yếu tố trong đó {-1,0,1}^mcó phủ định cũng {-1,0,1}^mchỉ cần lưu trữ một trong hai.
  • Tôi cũng cải thiện các yêu cầu về bộ nhớ và hiệu suất bằng cách sử dụng triển khai hashmap tùy chỉnh. Để kiểm tra 36/19 yêu cầu lưu trữ 3 ^ 18 khoản tiền và 3 ^ 18 dài gần 3 GB mà không cần bất kỳ chi phí nào - Tôi đã cho nó 6GB heap vì 4GB không đủ; để tiến xa hơn (ví dụ: kiểm tra 38/20) trong vòng 8GB RAM sẽ yêu cầu tối ưu hóa hơn nữa để lưu trữ int chứ không phải dài. Với 20 bit được yêu cầu để nói tập hợp con nào tạo ra tổng sẽ để lại 12 bit cộng với các bit ẩn từ nhóm; Tôi sợ rằng sẽ có quá nhiều va chạm sai để có được bất kỳ cú đánh nào.
  • Vì trọng lượng của các bằng chứng cho thấy rằng chúng ta nên xem xét 2n/(n+1), tôi tăng tốc mọi thứ bằng cách chỉ kiểm tra điều đó.
  • Có một số đầu ra thống kê không cần thiết nhưng yên tâm.
import java.util.*;

// Aiming to find a solution for (2n, n+1).
public class PPCG41021_QRTernary_FixedDensity {
    private static final int N = 36;
    private static int density;
    private static long start;
    private static long nextProgressReport;

    public static void main(String[] args) {
        start = System.nanoTime();
        nextProgressReport = start + 5 * 60 * 1000000000L;

        // 0, -1, 1, -2, 2, ...
        for (int i = 0; i < N - 1; i++) {
            int off = i >> 1;
            if ((i & 1) == 1) off = ~off;
            density = (N >> 1) + off;

            // Iterate over Lyndon words of length N and given density.
            for (int j = 0; j < N; j++) a[j] = j < N - density ? '0' : '1';
            c = 1;
            Bs[1] = N - density;
            Bt[1] = density;
            gen(N - density, density, 1);
            System.out.println("----");
        }

        System.out.println("Finished in " + (System.nanoTime() - start)/1000000 + " ms");
    }

    private static int c;
    private static int[] Bs = new int[N + 1], Bt = new int[N + 1];
    private static char[] a = new char[N];
    private static void gen(int s, int t, int r) {
        if (s > 0 && t > 0) {
            int j = oracle(s, t, r);
            for (int i = t - 1; i >= j; i--) {
                updateBlock(s, t, i);
                char tmp = a[s - 1]; a[s - 1] = a[s+t-i - 1]; a[s+t-i - 1] = tmp;
                gen(s-1, t-i, testSuffix(r) ? c-1 : r);
                tmp = a[s - 1]; a[s - 1] = a[s+t-i - 1]; a[s+t-i - 1] = tmp;
                restoreBlock(s, t, i);
            }
        }
        visit();
    }

    private static int oracle(int s, int t, int r) {
        int j = pseudoOracle(s, t, r);
        updateBlock(s, t, j);
        int p = testNecklace(testSuffix(r) ? c - 1 : r);
        restoreBlock(s, t, j);
        return p == N ? j : j + 1;
    }

    private static int pseudoOracle(int s, int t, int r) {
        if (s == 1) return t;
        if (c == 1) return s == 2 ? N / 2 : 1;
        if (s - 1 > Bs[r] + 1) return 0;
        if (s - 1 == Bs[r] + 1) return cmpPair(s-1, t, Bs[c-1]+1, Bt[c-1]) <= 0 ? 0 : 1;
        if (s - 1 == Bs[r]) {
            if (s == 2) return Math.max(t - Bt[r], (t+1) >> 1);
            return Math.max(t - Bt[r], (cmpPair(s-1, t, Bs[c-1] + 1, Bt[c-1]) <= 0) ? 0 : 1); 
        }
        if (s == Bs[r]) return t;
        throw new UnsupportedOperationException("Hit the case not covered by the paper or its accompanying code");
    }

    private static int testNecklace(int r) {
        if (density == 0 || density == N) return 1;
        int p = 0;
        for (int i = 0; i < c; i++) {
            if (r - i <= 0) r += c;
            if (cmpBlocks(c-i, r-i) < 0) return 0;
            if (cmpBlocks(c-i, r-1) > 0) return N;
            if (r < c) p += Bs[r-i] + Bt[r-i];
        }
        return p;
    }

    private static int cmpPair(int a1, int a2, int b1, int b2) {
        if (a1 < b1) return -1;
        if (a1 > b1) return 1;
        if (a2 < b2) return -1;
        if (a2 > b2) return 1;
        return 0;
    }

    private static int cmpBlocks(int i, int j) {
        return cmpPair(Bs[i], Bt[i], Bs[j], Bt[j]);
    }

    private static boolean testSuffix(int r) {
        for (int i = 0; i < r; i++) {
            if (c - 1 - i == r) return true;
            if (cmpBlocks(c-1-i, r-i) < 0) return false;
            if (cmpBlocks(c-1-i, r-1) > 0) return true;
        }
        return false;
    }

    private static void updateBlock(int s, int t, int i) {
        if (i == 0 && c > 1) {
            Bs[c-1]++;
            Bs[c] = s - 1;
        }
        else {
            Bs[c] = 1;
            Bt[c] = i;
            Bs[c+1] = s-1;
            Bt[c+1] = t-i;
            c++;
        }
    }

    private static void restoreBlock(int s, int t, int i) {
        if (i == 0 && (c > 0 || (Bs[1] != 1 || Bt[1] != 0))) {
            Bs[c-1]--;
            Bs[c] = s;
        }
        else {
            Bs[c-1] = s;
            Bt[c-1] = t;
            c--;
        }
    }

    private static long[] stats = new long[N/2+1];
    private static long visited = 0;
    private static void visit() {
        String word = new String(a);

        visited++;
        if (precedesReversal(word) && testTernary(word)) System.out.println(word + " after " + (System.nanoTime() - start)/1000000 + " ms");
        if (System.nanoTime() > nextProgressReport) {
            System.out.println("Progress: visited " + visited + "; stats " + Arrays.toString(stats) + " after " + (System.nanoTime() - start)/1000000 + " ms");
             nextProgressReport += 5 * 60 * 1000000000L;
        }
    }

    private static boolean precedesReversal(String w) {
        int n = w.length();
        StringBuilder rev = new StringBuilder(w);
        rev.reverse();
        rev.append(rev, 0, n);
        for (int i = 0; i < n; i++) {
            if (rev.substring(i, i + n).compareTo(w) < 0) return false;
        }
        return true;
    }

    private static boolean testTernary(String word) {
        int n = word.length();
        String rep = word + word;

        int base = 1;
        for (char ch : word.toCharArray()) base += ch & 1;

        // Operating base b for b up to 32 implies that we can multiply by b modulo p<2^57 without overflowing a long.
        // We're storing 3^(n/2) ~= 2^(0.8*n) sums, so while n < 35.6 we don't get *too* bad a probability of false reject.
        // (In fact the birthday paradox assumes independence, and our values aren't independent, so we're better off than that).
        long p = (1L << 57) - 13;
        long[] basis = new long[n];
        basis[0] = 1;
        for (int i = 1; i < basis.length; i++) basis[i] = (basis[i-1] * base) % p;

        int rows = n / 2 + 1;
        long[] colVals = new long[n];
        for (int col = 0; col < n; col++) {
            for (int row = 0; row < rows; row++) {
                colVals[col] = (colVals[col] + basis[row] * (rep.charAt(row + col) & 1)) % p;
            }
        }

        MapInt57Int27 map = new MapInt57Int27();
        // Special-case the initial insertion.
        int[] oldLens = new int[map.entries.length];
        int[] oldSupercounts = new int[1 << 10];
        {
            // count = 1
            for (int k = 0; k < n/2; k++) {
                int val = 1 << (25 - k);
                if (!map.put(colVals[k], val)) { stats[1]++; return false; }
                if (!map.put(colVals[k + n/2], val + (1 << 26))) { stats[1]++; return false; }
            }
        }
        final long keyMask = (1L << 37) - 1;
        for (int count = 2; count <= n/2; count++) {
            int[] lens = map.counts.clone();
            int[] supercounts = map.supercounts.clone();
            for (int sup = 0; sup < 1 << 10; sup++) {
                int unaccountedFor = supercounts[sup] - oldSupercounts[sup];
                for (int supi = 0; supi < 1 << 10 && unaccountedFor > 0; supi++) {
                    int i = (sup << 10) + supi;
                    int stop = lens[i];
                    unaccountedFor -= stop - oldLens[i];
                    for (int j = oldLens[i]; j < stop; j++) {
                        long existingKV = map.entries[i][j];
                        long existingKey = ((existingKV & keyMask) << 20) + i;
                        int existingVal = (int)(existingKV >>> 37);

                        // For each possible prepend...
                        int half = (existingVal >> 26) * n/2;
                        // We have 27 bits of key, of which the top marks the half, so 26 bits. That means there are 6 bits at the top which we need to not count.
                        int k = Integer.numberOfLeadingZeros(existingVal << 6) - 1;
                        while (k >= 0) {
                            int newVal = existingVal | (1 << (25 - k));
                            long pos = (existingKey + colVals[k + half]) % p;
                            if (pos << 1 > p) pos = p - pos;
                            if (pos == 0 || !map.put(pos, newVal)) { stats[count]++; return false; }
                            long neg = (p - existingKey + colVals[k + half]) % p;
                            if (neg << 1 > p) neg = p - neg;
                            if (neg == 0 || !map.put(neg, newVal)) { stats[count]++; return false; }
                            k--;
                        }
                    }
                }
            }
            oldLens = lens;
            oldSupercounts = supercounts;
        }

        stats[n/2]++;
        return true;
    }

    static class MapInt57Int27 {
        private long[][] entries;
        private int[] counts;
        private int[] supercounts;

        public MapInt57Int27() {
            entries = new long[1 << 20][];
            counts = new int[1 << 20];
            supercounts = new int[1 << 10];
        }

        public boolean put(long key, int val) {
            int bucket = (int)(key & (entries.length - 1));
            long insert = (key >>> 20) | (((long)val) << 37);
            final long mask = (1L << 37) - 1;

            long[] chain = entries[bucket];
            if (chain == null) {
                chain = new long[16];
                entries[bucket] = chain;
                chain[0] = insert;
                counts[bucket]++;
                supercounts[bucket >> 10]++;
                return true;
            }

            int stop = counts[bucket];
            for (int i = 0; i < stop; i++) {
                if ((chain[i] & mask) == (insert & mask)) {
                    return false;
                }
            }

            if (stop == chain.length) {
                long[] newChain = new long[chain.length < 512 ? chain.length << 1 : chain.length + 512];
                System.arraycopy(chain, 0, newChain, 0, chain.length);
                entries[bucket] = newChain;
                chain = newChain;
            }
            chain[stop] = insert;
            counts[bucket]++;
            supercounts[bucket >> 10]++;
            return true;
        }
    }
}

Người đầu tiên được tìm thấy là

000001001010110001000101001111111111

và đó là cú đánh duy nhất trong 15 giờ.

Người chiến thắng nhỏ hơn:

4/3:    0111                       (plus 8 different 8/6)
9/6:    001001011                  (and 5 others)
11/7:   00010100111                (and 3 others)
13/8:   0001001101011              (and 5 others)
15/9:   000010110110111            (and 21 others)
16/9:   0000101110111011           (and 1 other)
20/11:  00000101111011110111       (and others)
22/12:  0000001100110011101011     (and others)
24/13:  000000101011101011101011   (and others)
26/14:  00000001101110010011010111 (and others)
28/15:  0000000010000111100111010111 (and others)
30/16:  000000001011001110011010101111 (and probably others)
32/17:  00001100010010100100101011111111 (and others)
34/18:  0000101000100101000110010111111111 (and others)

Đây là một cải tiến tốt. Có vẻ như sử dụng các từ Lyndon có nghĩa là bạn chỉ cần kiểm tra khoảng 2 ^ n / n chuỗi nhị phân cho hàng đầu tiên, thay vì 2 ^ n.

Vì bạn đang sử dụng từng chữ số của BigInteger làm ô ma trận, sẽ không có câu trả lời sai khi n> 10?
kennytm

@KennyTM, lưu ý rằng tham số thứ hai là cơ số. Có một lỗi nhỏ: Tôi nên sử dụng nthay vì rows, mặc dù nó không an toàn theo nghĩa là nó sẽ loại bỏ các giải pháp hợp lệ thay vì chấp nhận các giải pháp không hợp lệ. Nó cũng không ảnh hưởng đến kết quả.
Peter Taylor

1
Tôi nghĩ rằng chúng tôi thực tế bị giới hạn ở điểm này, vì việc kiểm tra thuộc tính X rất tốn thời gian, trừ khi chúng tôi tìm thấy một điều kiện tương đương khác có thể được đánh giá nhanh hơn. Đó là lý do tại sao tôi rất háo hức khi thấy rằng "không phải là số nguyên tố" ngụ ý tài sản X = D
justhalf 6/11 '

1
@SuboptimusPrime, tôi đã tìm thấy nó tại people.math.sfu.ca/~kya17/teaching/math343/16-343.pdf và đã sửa một lỗi. Điều thú vị là thuật toán mà tôi hiện đang sử dụng để lặp qua các từ Lyndon là một trong những loại thuật toán có liên quan cũng có các tập con k-of-n, vì vậy tôi có thể có thể cấu trúc lại và chia sẻ một số mã.
Peter Taylor

9

Trăn 2 - 21/12

Trong quá trình chứng minh rằng 2-(3/n) luôn tồn tại cho bất kỳn

Lấy cảm hứng từ câu hỏi này , tôi đã sử dụng De Bruijn Sequence để vũ phu các ma trận có thể. Và sau khi bruteforcing chon=6,7,8,9,10 , tôi tìm thấy một mô hình mà giải pháp cao nhất luôn luôn có hình dạng (n, 2n-3).

Vì vậy, tôi đã tạo ra một phương pháp khác để đánh bại hình dạng của ma trận đó và sử dụng đa xử lý để tăng tốc mọi thứ, vì nhiệm vụ này có tính phân phối cao. Trong Ubuntu 16 lõi, nó có thể tìm giải pháp chon=12 trong khoảng 4 phút:

Đang thử (0, 254)
Đang thử (254, 509)
Đang thử (509, 764)
Đang thử (764, 1018)
Đang thử (1018, 1273)
Cố gắng (1273, 1528)
Cố gắng (1528, 1782)
Cố gắng (1782, 2037)
Cố gắng (2037, 2292)
Đang thử (2292, 2546)
Đang thử (2546, 2801)
Đang thử (2801, 3056)
Đang thử (3056, 3310)
Đang thử (3820, 4075)
Đang thử (3565, 3820)
Đang thử (3310, 3565)
(1625, 1646)
[[0 0 0 1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0]
 [0 0 1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0]
 [0 1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0]
 [1 0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0]
 [0 0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1]
 [0 1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0]
 [1 0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0]
 [0 1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1]
 [1 1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0]
 [1 1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 1]
 [1 1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 1 1]
 [1 0 0 0 1 0 0 1 1 0 0 0 0 1 0 0 1 0 1 1 1]]
(12, 21)
Điểm: 1.7500

4m9.121 thực
người dùng 42m47.472s
hệ thống 0m5.780

Phần lớn tính toán đi để kiểm tra thuộc tính X, yêu cầu kiểm tra tất cả các tập con (có 2^(2n-3)tập con)

Lưu ý rằng tôi xoay hàng đầu tiên sang trái, không phải bên phải như trong câu hỏi. Nhưng những điều này là tương đương vì bạn chỉ có thể đảo ngược toàn bộ ma trận. =)

Mật mã:

import math
import numpy as np
from itertools import combinations
from multiprocessing import Process, Queue, cpu_count

def de_bruijn(k, n):
    """
    De Bruijn sequence for alphabet k
    and subsequences of length n.
    """
    alphabet = list(range(k))
    a = [0] * k * n
    sequence = []
    def db(t, p):
        if t > n:
            if n % p == 0:
                for j in range(1, p + 1):
                    sequence.append(a[j])
        else:
            a[t] = a[t - p]
            db(t + 1, p)
            for j in range(a[t - p] + 1, k):
                a[t] = j
                db(t + 1, t)
    db(1, 1)
    return sequence

def generate_cyclic_matrix(seq, n):
    result = []
    for i in range(n):
        result.append(seq[i:]+seq[:i])
    return np.array(result)

def generate_cyclic_matrix_without_property_x(n=3, n_jobs=-1):
    seq = de_bruijn(2,n)
    seq = seq + seq[:n/2]
    max_idx = len(seq)
    max_score = 1
    max_matrix = np.array([[]])
    max_ij = (0,0)
    workers = []
    queue = Queue()
    if n_jobs < 0:
        n_jobs += cpu_count()+1
    for i in range(n_jobs):
        worker = Process(target=worker_function, args=(seq,i*(2**n-2*n+3)/n_jobs, (i+1)*(2**n-2*n+3)/n_jobs, n, queue))
        workers.append(worker)
        worker.start()
    (result, max_ij) = queue.get()
    for worker in workers:
        worker.terminate()
    return (result, max_ij)

def worker_function(seq,min_idx,max_idx,n,queue):
    print 'Trying (%d, %d)' % (min_idx, max_idx)
    for i in range(min_idx, max_idx):
        j = i+2*n-3
        result = generate_cyclic_matrix(seq[i:j], n)
        if has_property_x(result):
            continue
        else:
            queue.put( (result, (i,j)) )
            return

def has_property_x(mat):
    vecs = zip(*mat)
    vector_sums = set()
    for i in range(1, len(vecs)+1):
        for combination in combinations(vecs, i):
            vector_sum = tuple(sum(combination, np.array([0]*len(mat))))
            if vector_sum in vector_sums:
                return True
            else:
                vector_sums.add(vector_sum)
    return False

def main():
    import sys
    n = int(sys.argv[1])
    if len(sys.argv) > 2:
        n_jobs = int(sys.argv[2])
    else:
        n_jobs = -1
    (matrix, ij) = generate_cyclic_matrix_without_property_x(n, n_jobs)
    print ij
    print matrix
    print matrix.shape
    print 'Score: %.4f' % (float(matrix.shape[1])/matrix.shape[0])

if __name__ == '__main__':
    main()

Câu trả lời cũ, để tham khảo

Giải pháp tối ưu cho đến nay ( n=10):

(855, 872)
[[1 1 0 1 0 1 0 0 1 1 1 1 0 1 1 1 0]
 [1 0 1 0 1 0 0 1 1 1 1 0 1 1 1 0 1]
 [0 1 0 1 0 0 1 1 1 1 0 1 1 1 0 1 1]
 [1 0 1 0 0 1 1 1 1 0 1 1 1 0 1 1 0]
 [0 1 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1]
 [1 0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 0]
 [0 0 1 1 1 1 0 1 1 1 0 1 1 0 1 0 1]
 [0 1 1 1 1 0 1 1 1 0 1 1 0 1 0 1 0]
 [1 1 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0]
 [1 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1]]
(10, 17)
Điểm: 1.7000

Dành cho n=7:

(86, 97)
[[0 1 1 1 0 1 0 0 1 1 1]
 [1 1 1 0 1 0 0 1 1 1 0]
 [1 1 0 1 0 0 1 1 1 0 1]
 [1 0 1 0 0 1 1 1 0 1 1]
 [0 1 0 0 1 1 1 0 1 1 1]
 [1 0 0 1 1 1 0 1 1 1 0]
 [0 0 1 1 1 0 1 1 1 0 1]]
(7, 11)
Điểm: 1,5714

Một giải pháp có hình dạng như được mô tả bởi OP ( n=8):

(227, 239)
[[0 1 0 1 1 1 1 1 0 1 1 0]
 [1 0 1 1 1 1 1 0 1 1 0 0]
 [0 1 1 1 1 1 0 1 1 0 0 1]
 [1 1 1 1 1 0 1 1 0 0 1 0]
 [1 1 1 1 0 1 1 0 0 1 0 1]
 [1 1 1 0 1 1 0 0 1 0 1 1]
 [1 1 0 1 1 0 0 1 0 1 1 1]
 [1 0 1 1 0 0 1 0 1 1 1 1]]
(8, 12)
Điểm: 1.5000

Nhưng một cái tốt hơn ( n=8):

(95, 108)
[[0 1 1 0 0 1 0 0 0 1 1 0 1]
 [1 1 0 0 1 0 0 0 1 1 0 1 0]
 [1 0 0 1 0 0 0 1 1 0 1 0 1]
 [0 0 1 0 0 0 1 1 0 1 0 1 1]
 [0 1 0 0 0 1 1 0 1 0 1 1 0]
 [1 0 0 0 1 1 0 1 0 1 1 0 0]
 [0 0 0 1 1 0 1 0 1 1 0 0 1]
 [0 0 1 1 0 1 0 1 1 0 0 1 0]]
(8, 13)
Điểm: 1,6250

Nó cũng tìm thấy một giải pháp tối ưu khác tại n=9:

(103, 118)
[[0 1 0 1 1 1 0 0 0 0 1 1 0 0 1]
 [1 0 1 1 1 0 0 0 0 1 1 0 0 1 0]
 [0 1 1 1 0 0 0 0 1 1 0 0 1 0 1]
 [1 1 1 0 0 0 0 1 1 0 0 1 0 1 0]
 [1 1 0 0 0 0 1 1 0 0 1 0 1 0 1]
 [1 0 0 0 0 1 1 0 0 1 0 1 0 1 1]
 [0 0 0 0 1 1 0 0 1 0 1 0 1 1 1]
 [0 0 0 1 1 0 0 1 0 1 0 1 1 1 0]
 [0 0 1 1 0 0 1 0 1 0 1 1 1 0 0]]
(9, 15)
Điểm: 1.6667

Mã như sau. Đó chỉ là sức mạnh vũ phu, nhưng ít nhất nó có thể tìm thấy thứ gì đó tốt hơn yêu cầu của OP =)

import numpy as np
from itertools import combinations

def de_bruijn(k, n):
    """
    De Bruijn sequence for alphabet k
    and subsequences of length n.
    """
    alphabet = list(range(k))
    a = [0] * k * n
    sequence = []
    def db(t, p):
        if t > n:
            if n % p == 0:
                for j in range(1, p + 1):
                    sequence.append(a[j])
        else:
            a[t] = a[t - p]
            db(t + 1, p)
            for j in range(a[t - p] + 1, k):
                a[t] = j
                db(t + 1, t)
    db(1, 1)
    return sequence

def generate_cyclic_matrix(seq, n):
    result = []
    for i in range(n):
        result.append(seq[i:]+seq[:i])
    return np.array(result)

def generate_cyclic_matrix_without_property_x(n=3):
    seq = de_bruijn(2,n)
    max_score = 0
    max_matrix = []
    max_ij = (0,0)
    for i in range(2**n+1):
        for j in range(i+n, 2**n+1):
            score = float(j-i)/n
            if score <= max_score:
                continue
            result = generate_cyclic_matrix(seq[i:j], n)
            if has_property_x(result):
                continue
            else:
                if score > max_score:
                    max_score = score
                    max_matrix = result
                    max_ij = (i,j)
    return (max_matrix, max_ij)

def has_property_x(mat):
    vecs = zip(*mat)
    vector_sums = set()
    for i in range(1, len(vecs)):
        for combination in combinations(vecs, i):
            vector_sum = tuple(sum(combination, np.array([0]*len(mat))))
            if vector_sum in vector_sums:
                return True
            else:
                vector_sums.add(vector_sum)
    return False

def main():
    import sys
    n = int(sys.argv[1])
    (matrix, ij) = generate_cyclic_matrix_without_property_x(n)
    print ij
    print matrix
    print matrix.shape
    print 'Score: %.4f' % (float(matrix.shape[1])/matrix.shape[0])

if __name__ == '__main__':
    main()

Một khởi đầu tuyệt vời :)

2
@Lembik Bây giờ tôi có thể đánh bại gần như (giới hạn bởi thời gian tính toán) bất kỳ ai yêu cầu bất kỳ điểm nào dưới 2. =)
justhalf

Trong trường hợp đó, bạn có thể đánh bại 19/10 không?

@Lembik Tôi không nghĩ là tôi có thể. Nó đòi hỏi n >= 31, ngụ ý rằng tôi cần kiểm tra các 2^(2n-3) = 2^59tổ hợp vectơ 31 chiều. Sẽ không kết thúc trong cuộc đời của chúng tôi = D
justhalf 5/11 '

2
Bạn có thể chứng minh rằng bạn luôn có thể có được ma trậnn*(2n-3)
xnor

7

24/13 26/14 28/15 30/16 32/17 (C #)

Chỉnh sửa: Đã xóa thông tin lỗi thời từ câu trả lời của tôi. Tôi đang sử dụng hầu hết cùng một thuật toán với Peter Taylor ( Chỉnh sửa: có vẻ như anh ấy hiện đang sử dụng thuật toán tốt hơn), mặc dù tôi đã thêm một số tối ưu hóa của riêng mình:

  • Tôi đã thực hiện chiến lược "đáp ứng ở giữa" để tìm kiếm các tập hợp cột có cùng tổng vectơ (được đề xuất bởi nhận xét của KennyTM này ). Chiến lược này đã cải thiện việc sử dụng bộ nhớ rất nhiều, nhưng nó khá chậm, vì vậy tôi đã thêm HasPropertyXFastchức năng, kiểm tra nhanh xem có tập hợp nhỏ nào có tổng bằng nhau hay không trước khi sử dụng phương pháp "đáp ứng ở giữa".
  • Trong khi lặp qua các tập hợp cột trong HasPropertyXFast hàm, tôi bắt đầu từ việc kiểm tra các tập hợp cột với 1 cột, sau đó với 2, 3, v.v. Hàm trả về ngay khi va chạm đầu tiên của tổng cột được tìm thấy. Trong thực tế, điều đó có nghĩa là tôi thường phải kiểm tra chỉ vài trăm hoặc hàng nghìn bộ cột chứ không phải hàng triệu.
  • Tôi đang sử dụng longcác biến để lưu trữ và so sánh toàn bộ các cột và tổng vector của chúng. Cách tiếp cận này ít nhất là một thứ tự cường độ nhanh hơn so với việc so sánh các cột dưới dạng mảng.
  • Tôi đã thêm triển khai hashset của riêng mình, được tối ưu hóa cho long kiểu dữ liệu và cho các kiểu sử dụng của tôi.
  • Tôi đang sử dụng lại 3 hàm băm giống nhau trong toàn bộ thời gian của ứng dụng để giảm số lượng phân bổ bộ nhớ và cải thiện hiệu suất.
  • Hỗ trợ đa luồng.

Đầu ra chương trình:

00000000000111011101010010011111
10000000000011101110101001001111
11000000000001110111010100100111
11100000000000111011101010010011
11110000000000011101110101001001
11111000000000001110111010100100
01111100000000000111011101010010
00111110000000000011101110101001
10011111000000000001110111010100
01001111100000000000111011101010
00100111110000000000011101110101
10010011111000000000001110111010
01001001111100000000000111011101
10100100111110000000000011101110
01010010011111000000000001110111
10101001001111100000000000111011
11010100100111110000000000011101
Score: 32/17 = 1,88235294117647
Time elapsed: 02:11:05.9791250

Mã số:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

class Program
{
    const int MaxWidth = 32;
    const int MaxHeight = 17;

    static object _lyndonWordLock = new object();

    static void Main(string[] args)
    {
        Stopwatch sw = Stopwatch.StartNew();
        double maxScore = 0;
        const int minHeight = 17; // 1
        for (int height = minHeight; height <= MaxHeight; height++)
        {
            Console.WriteLine("Row count = " + height);
            Console.WriteLine("Time elapsed: " + sw.Elapsed + "\r\n");

            int minWidth = Math.Max(height, (int)(height * maxScore) + 1);
            for (int width = minWidth; width <= MaxWidth; width++)
            {
#if MULTITHREADING
                int[,] matrix = FindMatrixParallel(width, height);
#else
                int[,] matrix = FindMatrix(width, height);
#endif
                if (matrix != null)
                {
                    PrintMatrix(matrix);
                    Console.WriteLine("Time elapsed: " + sw.Elapsed + "\r\n");
                    maxScore = (double)width / height;
                }
                else
                    break;
            }
        }
    }

#if MULTITHREADING
    static int[,] FindMatrixParallel(int width, int height)
    {
        _lyndonWord = 0;
        _stopSearch = false;

        int threadCount = Environment.ProcessorCount;
        Task<int[,]>[] tasks = new Task<int[,]>[threadCount];
        for (int i = 0; i < threadCount; i++)
            tasks[i] = Task<int[,]>.Run(() => FindMatrix(width, height));

        int index = Task.WaitAny(tasks);
        if (tasks[index].Result != null)
            _stopSearch = true;

        Task.WaitAll(tasks);
        foreach (Task<int[,]> task in tasks)
            if (task.Result != null)
                return task.Result;

        return null;
    }

    static volatile bool _stopSearch;
#endif

    static int[,] FindMatrix(int width, int height)
    {
#if MULTITHREADING
        _columnSums = new LongSet();
        _left = new LongSet();
        _right = new LongSet();
#endif

        foreach (long rowTemplate in GetLyndonWords(width))
        {
            int[,] matrix = new int[width, height];
            for (int x = 0; x < width; x++)
            {
                int cellValue = (int)(rowTemplate >> (width - 1 - x)) % 2;
                for (int y = 0; y < height; y++)
                    matrix[(x + y) % width, y] = cellValue;
            }

            if (!HasPropertyX(matrix))
                return matrix;

#if MULTITHREADING
            if (_stopSearch)
                return null;
#endif
        }

        return null;
    }

#if MULTITHREADING
    static long _lyndonWord;
#endif

    static IEnumerable<long> GetLyndonWords(int length)
    {
        long lyndonWord = 0;
        long max = (1L << (length - 1)) - 1;
        while (lyndonWord <= max)
        {
            if ((lyndonWord % 2 != 0) && PrecedesReversal(lyndonWord, length))
                yield return lyndonWord;

#if MULTITHREADING
            lock (_lyndonWordLock)
            {
                if (_lyndonWord <= max)
                    _lyndonWord = NextLyndonWord(_lyndonWord, length);
                else
                    yield break;

                lyndonWord = _lyndonWord;
            }
#else
            lyndonWord = NextLyndonWord(lyndonWord, length);
#endif
        }
    }

    static readonly int[] _lookup =
    {
        32, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4, 7, 17,
        0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5, 20, 8, 19, 18
    };

    static int NumberOfTrailingZeros(uint i)
    {
        return _lookup[(i & -i) % 37];
    }

    static long NextLyndonWord(long w, int length)
    {
        if (w == 0)
            return 1;

        int currentLength = length - NumberOfTrailingZeros((uint)w);
        while (currentLength < length)
        {
            w += w >> currentLength;
            currentLength *= 2;
        }

        w++;

        return w;
    }

    private static bool PrecedesReversal(long lyndonWord, int length)
    {
        int shift = length - 1;

        long reverse = 0;
        for (int i = 0; i < length; i++)
        {
            long bit = (lyndonWord >> i) % 2;
            reverse |= bit << (shift - i);
        }

        for (int i = 0; i < length; i++)
        {
            if (reverse < lyndonWord)
                return false;

            long bit = reverse % 2;
            reverse /= 2;
            reverse += bit << shift;
        }

        return true;
    }

#if MULTITHREADING
    [ThreadStatic]
#endif
    static LongSet _left = new LongSet();
#if MULTITHREADING
    [ThreadStatic]
#endif
    static LongSet _right = new LongSet();

    static bool HasPropertyX(int[,] matrix)
    {
        long[] matrixColumns = GetMatrixColumns(matrix);
        if (matrixColumns.Length == 1)
            return false;

        return HasPropertyXFast(matrixColumns) || MeetInTheMiddle(matrixColumns);
    }

    static bool MeetInTheMiddle(long[] matrixColumns)
    {
        long[] leftColumns = matrixColumns.Take(matrixColumns.Length / 2).ToArray();
        long[] rightColumns = matrixColumns.Skip(matrixColumns.Length / 2).ToArray();

        if (PrepareHashSet(leftColumns, _left) || PrepareHashSet(rightColumns, _right))
            return true;

        foreach (long columnSum in _left.GetValues())
            if (_right.Contains(columnSum))
                return true;

        return false;
    }

    static bool PrepareHashSet(long[] columns, LongSet sums)
    {
        int setSize = (int)System.Numerics.BigInteger.Pow(3, columns.Length);
        sums.Reset(setSize, setSize);
        foreach (long column in columns)
        {
            foreach (long sum in sums.GetValues())
                if (!sums.Add(sum + column) || !sums.Add(sum - column))
                    return true;

            if (!sums.Add(column) || !sums.Add(-column))
                return true;
        }

        return false;
    }

#if MULTITHREADING
    [ThreadStatic]
#endif
    static LongSet _columnSums = new LongSet();

    static bool HasPropertyXFast(long[] matrixColumns)
    {
        int width = matrixColumns.Length;

        int maxColumnCount = width / 3;
        _columnSums.Reset(width, SumOfBinomialCoefficients(width, maxColumnCount));

        int resetBit, setBit;
        for (int k = 1; k <= maxColumnCount; k++)
        {
            uint columnMask = (1u << k) - 1;
            long sum = 0;
            for (int i = 0; i < k; i++)
                sum += matrixColumns[i];

            while (true)
            {
                if (!_columnSums.Add(sum))
                    return true;
                if (!NextColumnMask(columnMask, k, width, out resetBit, out setBit))
                    break;
                columnMask ^= (1u << resetBit) ^ (1u << setBit);
                sum = sum - matrixColumns[resetBit] + matrixColumns[setBit];
            }
        }

        return false;
    }

    // stolen from Peter Taylor
    static bool NextColumnMask(uint mask, int k, int n, out int resetBit, out int setBit)
    {
        int gap = NumberOfTrailingZeros(~mask);
        int next = 1 + NumberOfTrailingZeros(mask & (mask + 1));

        if (((k - gap) & 1) == 0)
        {
            if (gap == 0)
            {
                resetBit = next - 1;
                setBit = next - 2;
            }
            else if (gap == 1)
            {
                resetBit = 0;
                setBit = 1;
            }
            else
            {
                resetBit = gap - 2;
                setBit = gap;
            }
        }
        else
        {
            if (next == n)
            {
                resetBit = 0;
                setBit = 0;
                return false;
            }

            if ((mask & (1 << next)) == 0)
            {
                if (gap == 0)
                {
                    resetBit = next - 1;
                    setBit = next;
                }
                else
                {
                    resetBit = gap - 1;
                    setBit = next;
                }
            }
            else
            {
                resetBit = next;
                setBit = gap;
            }
        }

        return true;
    }

    static long[] GetMatrixColumns(int[,] matrix)
    {
        int width = matrix.GetLength(0);
        int height = matrix.GetLength(1);

        long[] result = new long[width];
        for (int x = 0; x < width; x++)
        {
            long column = 0;
            for (int y = 0; y < height; y++)
            {
                column *= 13;
                if (matrix[x, y] == 1)
                    column++;
            }

            result[x] = column;
        }

        return result;
    }

    static int SumOfBinomialCoefficients(int n, int k)
    {
        int result = 0;
        for (int i = 0; i <= k; i++)
            result += BinomialCoefficient(n, i);
        return result;
    }

    static int BinomialCoefficient(int n, int k)
    {
        long result = 1;
        for (int i = n - k + 1; i <= n; i++)
            result *= i;
        for (int i = 2; i <= k; i++)
            result /= i;
        return (int)result;
    }

    static void PrintMatrix(int[,] matrix)
    {
        int width = matrix.GetLength(0);
        int height = matrix.GetLength(1);

        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
                Console.Write(matrix[x, y]);
            Console.WriteLine();
        }

        Console.WriteLine("Score: {0}/{1} = {2}", width, height, (double)width / height);
    }
}


class LongSet
{
    private static readonly int[] primes =
    {
        17, 37, 67, 89, 113, 149, 191, 239, 307, 389, 487, 613, 769, 967, 1213, 1523, 1907,
        2389, 2999, 3761, 4703, 5879, 7349, 9187, 11489, 14369, 17971, 22469, 28087, 35111,
        43889, 54869, 68597, 85751, 107197, 133999, 167521, 209431, 261791, 327247, 409063,
        511333, 639167, 798961, 998717, 1248407, 1560511, 1950643, 2438309, 3047909,
        809891, 4762367, 5952959, 7441219, 9301529, 11626913, 14533661, 18167089, 22708867,
        28386089, 35482627, 44353297, 55441637, 69302071, 86627603, 108284507, 135355669,
        169194593, 211493263, 264366593, 330458263, 413072843, 516341057, 645426329,
        806782913, 1008478649, 1260598321
    };

    private int[] _buckets;
    private int[] _nextItemIndexes;
    private long[] _items;
    private int _count;
    private int _minCapacity;
    private int _maxCapacity;
    private int _currentCapacity;

    public LongSet()
    {
        Initialize(0, 0);
    }

    private int GetPrime(int capacity)
    {
        foreach (int prime in primes)
            if (prime >= capacity)
                return prime;

        return int.MaxValue;
    }

    public void Reset(int minCapacity, int maxCapacity)
    {
        if (maxCapacity > _maxCapacity)
            Initialize(minCapacity, maxCapacity);
        else
            ClearBuckets();
    }

    private void Initialize(int minCapacity, int maxCapacity)
    {
        _minCapacity = GetPrime(minCapacity);
        _maxCapacity = GetPrime(maxCapacity);
        _currentCapacity = _minCapacity;

        _buckets = new int[_maxCapacity];
        _nextItemIndexes = new int[_maxCapacity];
        _items = new long[_maxCapacity];
        _count = 0;
    }

    private void ClearBuckets()
    {
        Array.Clear(_buckets, 0, _currentCapacity);
        _count = 0;
        _currentCapacity = _minCapacity;
    }

    public bool Add(long value)
    {
        int bucket = (int)((ulong)value % (ulong)_currentCapacity);
        for (int i = _buckets[bucket] - 1; i >= 0; i = _nextItemIndexes[i])
            if (_items[i] == value)
                return false;

        if (_count == _currentCapacity)
        {
            Grow();
            bucket = (int)((ulong)value % (ulong)_currentCapacity);
        }

        int index = _count;
        _items[index] = value;
        _nextItemIndexes[index] = _buckets[bucket] - 1;
        _buckets[bucket] = index + 1;
        _count++;

        return true;
    }

    private void Grow()
    {
        Array.Clear(_buckets, 0, _currentCapacity);

        const int growthFactor = 8;
        int newCapacity = GetPrime(_currentCapacity * growthFactor);
        if (newCapacity > _maxCapacity)
            newCapacity = _maxCapacity;
        _currentCapacity = newCapacity;

        for (int i = 0; i < _count; i++)
        {
            int bucket = (int)((ulong)_items[i] % (ulong)newCapacity);
            _nextItemIndexes[i] = _buckets[bucket] - 1;
            _buckets[bucket] = i + 1;
        }
    }

    public bool Contains(long value)
    {
        int bucket = (int)((ulong)value % (ulong)_buckets.Length);
        for (int i = _buckets[bucket] - 1; i >= 0; i = _nextItemIndexes[i])
            if (_items[i] == value)
                return true;

        return false;
    }

    public IReadOnlyList<long> GetValues()
    {
        return new ArraySegment<long>(_items, 0, _count);
    }
}

Tập tin cấu hình:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

Về mặt nào đó bạn dường như đã bi quan hơn là tối ưu hóa. Điều duy nhất thực sự trông giống như một sự tối ưu hóa là cho phép các bit xung đột bằng cách sử dụng ulongvà để thay đổi bọc thay vì sử dụng BigInteger.
Peter Taylor

@PeterTaylor Tối ưu hóa quan trọng nhất là trong chức năng HasPropertyX. Hàm trả về ngay khi tìm thấy xung đột đầu tiên của tổng cột (không giống như hàm sốLyndonWord của bạn). Tôi cũng đã sắp xếp các mặt nạ cột theo cách mà trước tiên chúng tôi kiểm tra các bộ cột có nhiều khả năng va chạm. Hai tối ưu hóa đã cải thiện hiệu suất theo một thứ tự cường độ.
Suboptimus Prime

Mặc dù thay đổi hiệu suất thường gây ngạc nhiên, nhưng về nguyên tắc, việc hủy bỏ sớm không nên cung cấp nhiều hơn hệ số 2 và GetSumOfColumnsthêm một vòng lặp mà tôi dự kiến ​​sẽ tốn kém hơn yếu tố đó là 2. Việc sắp xếp mặt nạ nghe có vẻ thú vị: có thể bạn có thể chỉnh sửa câu trả lời để nói một chút về nó? (Và tại một thời điểm nào đó, tôi sẽ thử nghiệm một cách khác để thực hiện hủy bỏ sớm: lý do tôi không thể làm điều đó là Hashset không hỗ trợ lặp và sửa đổi đồng thời, nhưng tôi có ý tưởng để tránh sự cần thiết của trình lặp) .
Peter Taylor

2
@justhalf, sử dụng một cách tiếp cận Grey-esque cho iterating trên các tập con của một kích thước cố định thực sự đáng giá. Nó cho phép tôi tìm thấy 26/14 trong dưới 9 phút và 34 trong số đó trong hai giờ, tại thời điểm đó tôi đã hủy bỏ. Hiện đang thử nghiệm để xem liệu tôi có thể nhận được 28/15 trong một thời gian hợp lý không.
Peter Taylor

1
@Lembik, tôi đã khám phá hết 29/15 trong 75,5 giờ. 31/16 sẽ mất khoảng 3 lần thời gian dài - hơn một tuần. Cả hai chúng tôi đã thực hiện một số tối ưu kể từ khi tôi bắt đầu chạy thử nghiệm đó vào 29/15, vì vậy có lẽ nó sẽ giảm xuống còn một tuần nữa. Không có gì ngăn bạn biên dịch mã của tôi hoặc mã của SuboptimusPrime và tự chạy nó nếu bạn có một máy tính mà bạn có thể để lâu như vậy.
Peter Taylor
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.