Tic-tac-toe chỉ với chéo càng nhanh càng tốt


10

Theo yêu cầu của LukePeter Taylor bổ sung cho thử thách này.

Giới thiệu

Mọi người đều biết trò chơi tic-tac-toe, nhưng trong thử thách này, chúng tôi sẽ giới thiệu một chút thay đổi. Chúng tôi sẽ chỉ sử dụng chéo . Người đầu tiên đặt ba chữ thập liên tiếp bị mất. Một sự thật thú vị là số lượng vượt qua tối đa trước khi ai đó thua, bằng 6 :

X X -
X - X
- X X

Điều đó có nghĩa là đối với một bảng 3 x 3, số tiền tối đa là 6 . Vì vậy, với N = 3, chúng ta cần xuất 6.

Một ví dụ khác, cho N = 4 hoặc bảng 4 x 4:

X X - X
X X - X
- - - -
X X - X

Đây là một giải pháp tối ưu, bạn có thể thấy rằng số lượng chéo tối đa bằng 9 . Một giải pháp tối ưu cho bảng 12 x 12 là:

X - X - X - X X - X X -
X X - X X - - - X X - X
- X - X - X X - - - X X
X - - - X X - X X - X -
- X X - - - X - - - - X
X X - X X - X - X X - -
- - X X - X - X X - X X
X - - - - X - - - X X -
- X - X X - X X - - - X
X X - - - X X - X - X -
X - X X - - - X X - X X
- X X - X X - X - X - X

Kết quả này trong 74 .

Nhiệm vụ

Nhiệm vụ của bạn là tính toán kết quả nhanh nhất có thể. Tôi sẽ chạy mã của bạn trên trường hợp thử nghiệm 13. Điều này sẽ được thực hiện 5 lần và sau đó trung bình được thực hiện trong thời gian chạy. Đó là điểm số cuối cùng của bạn. Càng thấp, càng tốt.

Các trường hợp thử nghiệm

N     Output
1       1
2       4
3       6
4       9
5       16
6       20
7       26
8       36
9       42
10      52
11      64
12      74
13      86
14      100
15      114

Thông tin chi tiết có thể được tìm thấy tại https://oeis.org/A181018 .

Quy tắc

  • Đây là , vì vậy trình nhanh nhất sẽ thắng!
  • Bạn phải cung cấp một chương trình đầy đủ .
  • Vui lòng cung cấp cách tôi phải chạy chương trình. Tôi không quen thuộc với tất cả các ngôn ngữ lập trình và cách chúng hoạt động, vì vậy tôi cần một chút giúp đỡ ở đây.
  • Tất nhiên, mã của bạn cần tính toán kết quả chính xác cho từng trường hợp thử nghiệm.

Đệ trình:

  • frageum (C ++ 11): 28s
  • Peter Taylor (Java): 14m 31s


Đây không phải là một bản sao của câu hỏi thứ hai theo như tôi có thể nói, bạn vừa thay đổi điều kiện chiến thắng?
Blue

1
@muddyfish Mặc dù thử thách trông giống nhau, tôi có thể đảm bảo với bạn rằng cách tiếp cận cho thử thách này rất khác so với thử thách khác của tôi.
Ad Nam

3
@muddyfish Thảo luận meta có liên quan. "Chỉ cần thay đổi điều kiện chiến thắng" có thể là một thay đổi đáng kể cho một thách thức. Trong khi nó không có ý nghĩa để gửi một mã golf , nhanh nhất thuật toánnhanh nhất-code cho mọi thách thức có thể, có một số trường hợp, nơi khám phá một vấn đề từ hai góc có thể thêm rất nhiều giá trị cho trang web. Tôi nghĩ rằng đây là một trường hợp như vậy.
Martin Ender

1
Thử thách tuyệt vời! (+1)

Câu trả lời:


5

C ++ 11, 28

Điều này cũng sử dụng một phương pháp lập trình động dựa trên các hàng. Phải mất 28 giây để chạy với đối số 13 cho tôi. Thủ thuật yêu thích của tôi là nextchức năng sử dụng một số bashing để tìm cách sắp xếp hàng theo từ vựng tiếp theo thỏa mãn mặt nạ và quy tắc không có 3 hàng liên tiếp.

Hướng dẫn

  1. Cài đặt MinGW-w64 mới nhất với các luồng SEH và Posix
  2. Biên dịch chương trình với g++ -std=c++11 -march=native -O3 <filename>.cpp -o <executable name>
  3. Chạy với <executable name> <n>
#include <vector>
#include <stddef.h>
#include <iostream>
#include <string>

#ifdef _MSC_VER
#include <intrin.h>
#define popcount32 _mm_popcnt_u32
#else
#define popcount32 __builtin_popcount
#endif


using std::vector;

using row = uint32_t;
using xcount = uint8_t;

uint16_t rev16(uint16_t x) { // slow
    static const uint8_t revbyte[] {0,128,64,192,32,160,96,224,16,144,80,208,48,176,112,240,8,136,72,200,40,168,104,232,24,152,88,216,56,184,120,248,4,132,68,196,36,164,100,228,20,148,84,212,52,180,116,244,12,140,76,204,44,172,108,236,28,156,92,220,60,188,124,252,2,130,66,194,34,162,98,226,18,146,82,210,50,178,114,242,10,138,74,202,42,170,106,234,26,154,90,218,58,186,122,250,6,134,70,198,38,166,102,230,22,150,86,214,54,182,118,246,14,142,78,206,46,174,110,238,30,158,94,222,62,190,126,254,1,129,65,193,33,161,97,225,17,145,81,209,49,177,113,241,9,137,73,201,41,169,105,233,25,153,89,217,57,185,121,249,5,133,69,197,37,165,101,229,21,149,85,213,53,181,117,245,13,141,77,205,45,173,109,237,29,157,93,221,61,189,125,253,3,131,67,195,35,163,99,227,19,147,83,211,51,179,115,243,11,139,75,203,43,171,107,235,27,155,91,219,59,187,123,251,7,135,71,199,39,167,103,231,23,151,87,215,55,183,119,247,15,143,79,207,47,175,111,239,31,159,95,223,63,191,127,255};
    return uint16_t(revbyte[x >> 8]) | uint16_t(revbyte[x & 0xFF]) << 8;
}

// returns the next number after r that does not overlap the mask or have three 1's in a row
row next(row r, uint32_t m) {
    m |= r >> 1 & r >> 2;
    uint32_t x = (r | m) + 1;
    uint32_t carry = x & -x;
    return (r | carry) & -carry;
}

template<typename T, typename U> void maxequals(T& m, U v) {
    if (v > m)
        m = v;
}

struct tictac {
    const int n;
    vector<row> rows;
    size_t nonpal, nrows_c;
    vector<int> irow;
    vector<row> revrows;

    tictac(int n) : n(n) { }

    row reverse(row r) {
        return rev16(r) >> (16 - n);
    }

    vector<int> sols_1row() {
        vector<int> v(1 << n);
        for (uint32_t m = 0; !(m >> n); m++) {
            auto m2 = m;
            int n0 = 0;
            int score = 0;
            for (int i = n; i--; m2 >>= 1) {
                if (m2 & 1) {
                    n0 = 0;
                } else {
                    if (++n0 % 3)
                        score++;
                }
            }
            v[m] = score;
        }
        return v;
    }

    void gen_rows() {
        vector<row> pals;
        for (row r = 0; !(r >> n); r = next(r, 0)) {
            row rrev = reverse(r);
            if (r < rrev) {
                rows.push_back(r);
            } else if (r == rrev) {
                pals.push_back(r);
            }
        }
        nonpal = rows.size();
        for (row r : pals) {
            rows.push_back(r);
        }
        nrows_c = rows.size();
        for (int i = 0; i < nonpal; i++) {
            rows.push_back(reverse(rows[i]));
        }
        irow.resize(1 << n);
        for (int i = 0; i < rows.size(); i++) {
            irow[rows[i]] = i;
        }
        revrows.resize(1 << n);
        for (row r = 0; !(r >> n); r++) {
            revrows[r] = reverse(r);
        }
    }

    // find banned locations for 1's given 2 above rows
    uint32_t mask(row a, row b) {
        return ((a & b) | (a >> 1 & b) >> 1 | (a << 1 & b) << 1) /*& ((1 << n) - 1)*/;
    }

    int calc() {
        if (n < 3) {
            return n * n;
        }
        gen_rows();
        int tdim = n < 5 ? n : (n + 3) / 2;
        size_t nrows = rows.size();
        xcount* t = new xcount[2 * nrows * nrows_c]{};
#define tb(nr, i, j) t[nrows * (nrows_c * ((nr) & 1) + (i)) + (j)]

        // find optimal solutions given 2 rows for n x k grids where 3 <= k <= ceil(n/2) + 1

        {
            auto s1 = sols_1row();
            for (int i = 0; i < nrows_c; i++) {
                row a = rows[i];
                for (int j = 0; j < nrows; j++) {
                    row b = rows[j];
                    uint32_t m = mask(b, a) & ~(1 << n);
                    tb(3, i, j) = s1[m] + popcount32(a << 16 | b);
                }
            }
        }
        for (int r = 4; r <= tdim; r++) {
            for (int i = 0; i < nrows_c; i++) {
                row a = rows[i];
                for (int j = 0; j < nrows; j++) {
                    row b = rows[j];
                    bool rev = j >= nrows_c;
                    auto cj = rev ? j - nrows_c : j;
                    uint32_t m = mask(a, b);
                    for (row c = 0; !(c >> n); c = next(c, m)) {
                        row cc = rev ? revrows[c] : c;
                        int count = tb(r - 1, i, j) + popcount32(c);
                        maxequals(tb(r, cj, irow[cc]), count);
                    }
                }
            }
        }
        int ans = 0;
        if (tdim == n) { // small sizes
            for (int i = 0; i < nrows_c; i++) {
                for (int j = 0; j < nrows; j++) {
                    maxequals(ans, tb(n, i, j));
                }
            }
        } else {
            int tdim2 = n + 2 - tdim;
            // get final answer by joining two halves' solutions down the middle
            for (int i = 0; i < nrows_c; i++) {
                int apc = popcount32(rows[i]);
                for (int j = 0; j < nrows; j++) {
                    row b = rows[j];
                    int top = tb(tdim2, i, j);
                    int bottom = j < nrows_c ? tb(tdim, j, i) : tb(tdim, j - nrows_c, i < nonpal ? i + nrows_c : i);
                    maxequals(ans, top + bottom - apc - popcount32(b));
                }
            }
        }
        delete[] t;
        return ans;
    }
};


int main(int argc, char** argv) {
    int n;
    if (argc < 2 || (n = std::stoi(argv[1])) < 0 || n > 16) {
        return 1;
    }
    std::cout << tictac{ n }.calc() << '\n';
    return 0;
}

7

Java, 14m 31s

Đây thực chất là chương trình mà tôi đã đăng lên OEIS sau khi sử dụng nó để mở rộng trình tự, vì vậy đây là một tài liệu tham khảo tốt cho những người khác đánh bại. Tôi đã điều chỉnh nó để lấy kích thước bảng làm đối số dòng lệnh đầu tiên.

public class A181018 {
    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        System.out.println(calc(n));
    }

    private static int calc(int n) {
        if (n < 0) throw new IllegalArgumentException("n");
        if (n < 3) return n * n;

        // Dynamic programming approach: given two rows, we can enumerate the possible third row.
        // sc[i + rows.length * j] is the greatest score achievable with a board ending in rows[i], rows[j].
        int[] rows = buildRows(n);
        byte[] sc = new byte[rows.length * rows.length];
        for (int j = 0, k = 0; j < rows.length; j++) {
            int qsc = Integer.bitCount(rows[j]);
            for (int i = 0; i < rows.length; i++) sc[k++] = (byte)(qsc + Integer.bitCount(rows[i]));
        }

        int max = 0;
        for (int h = 2; h < n; h++) {
            byte[] nsc = new byte[rows.length * rows.length];
            for (int i = 0; i < rows.length; i++) {
                int p = rows[i];
                for (int j = 0; j < rows.length; j++) {
                    int q = rows[j];
                    // The rows which follow p,q cannot intersect with a certain mask.
                    int mask = (p & q) | ((p << 2) & (q << 1)) | ((p >> 2) & (q >> 1));
                    for (int k = 0; k < rows.length; k++) {
                        int r = rows[k];
                        if ((r & mask) != 0) continue;

                        int pqrsc = (sc[i + rows.length * j] & 0xff) + Integer.bitCount(r);
                        int off = j + rows.length * k;
                        if (pqrsc > nsc[off]) nsc[off] = (byte)pqrsc;
                        if (pqrsc > max) max = pqrsc;
                    }
                }
            }

            sc = nsc;
        }

        return max;
    }

    private static int[] buildRows(int n) {
        // Array length is a tribonacci number.
        int c = 1;
        for (int a = 0, b = 1, i = 0; i < n; i++) c = a + (a = b) + (b = c);

        int[] rows = new int[c];
        int i = 0, j = 1, val;
        while ((val = rows[i]) < (1 << (n - 1))) {
            if (val > 0) rows[j++] = val * 2;
            if ((val & 3) != 3) rows[j++] = val * 2 + 1;
            i++;
        }

        return rows;
    }
}

Lưu vào A181018.java; biên dịch như javac A181018.java; chạy như java A181018 13. Trên máy tính của tôi, mất khoảng 20 phút để thực hiện cho đầu vào này. Nó có lẽ sẽ có giá trị song song với nó.


Bạn đã chạy nó được bao lâu rồi? Bạn vẫn đang thêm các điều khoản vào OEIS, tôi thấy.
mbomb007

1
@ mbomb007, tôi vẫn không chạy nó. Như bạn có thể biết từ ngày OEIS, phải mất vài ngày để chạy n=16; Tôi đã ngoại suy rằng sẽ mất khoảng một tháng n=17, vì vậy tôi đã không cố gắng chạy nó vì điều đó. Việc sử dụng bộ nhớ cũng trở thành một mối phiền toái lớn. (PS Tôi hiện đang sử dụng 2 trong số 4 lõi của mình cho thử thách lập trình không phải PPCG: azspcs.com/Contest/Tetrahedra/Standings )
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.