โอเอกซ์ด้วยการข้ามเท่านั้น


32

บทนำ

ทุกคนรู้เกมโอเอกซ์ แต่ในความท้าทายนี้เราจะแนะนำการบิดเล็กน้อย เราจะใช้ไม้กางเขนเท่านั้น คนแรกที่ข้ามสามในแถวแพ้ ข้อเท็จจริงที่น่าสนใจคือจำนวนข้ามสูงสุดก่อนที่ใครบางคนจะสูญเสียเท่ากับ6 :

X X -
X - X
- X X

นั่นหมายความว่าสำหรับบอร์ด 3 x 3 จำนวนสูงสุดคือ 6 ดังนั้นสำหรับ N = 3 เราต้องเอาท์พุท 6

อีกตัวอย่างหนึ่งสำหรับ N = 4 หรือบอร์ด 4 x 4:

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

นี่คือทางออกที่ดีที่สุดที่คุณสามารถเห็นได้ว่าจำนวนเงินสูงสุดของไม้กางเขนเท่ากับ9 ทางออกที่ดีที่สุดสำหรับบอร์ด 12 x 12 คือ:

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

ผลนี้ใน74

งาน

งานง่าย ๆ โดยกำหนดเป็นจำนวนเต็มมากกว่า 0 ออกเอาท์พุต จำนวนการข้ามสูงสุดที่สามารถวางโดยไม่มี X สามตัวที่อยู่ติดกันในบรรทัดตามแนวแถวคอลัมน์หรือแนวทแยงมุม

กรณีทดสอบ

N     Output
1     1
2     4
3     6
4     9
5     16
6     20
7     26
8     36
9     42

ข้อมูลเพิ่มเติมสามารถดูได้ที่https://oeis.org/A181018 https://oeis.org/A181018

กฎระเบียบ

  • นี่คือดังนั้นการส่งที่มีจำนวนไบต์น้อยที่สุดจะชนะ!
  • คุณอาจมีฟังก์ชั่นหรือโปรแกรม

7
ดังนั้นคำถามเพียงแค่เดือดลงไปที่การใช้สูตรในหน้าเว็บที่คุณเชื่อมโยง ...
nicael

2
โพสต์ที่เกี่ยวข้องมากกว่าในวิชาคณิตศาสตร์
AdmBorkBork

7
@nicael เท่าที่ฉันเห็นบทความ OEIS มีขอบเขตที่ต่ำกว่าเท่านั้น
Martin Ender

6
คงจะเจ๋งที่เห็นนี่เป็นความท้าทายของรหัสที่เร็วที่สุด
ลุค

4
ไม่ใช่โซลูชัน codegolf แต่ฉันเล่นกับตัวแก้ปัญหา "visual" ในช่วงไม่กี่วันที่ผ่านมา คุณสามารถเข้าถึง jsfiddle ได้ที่นี่: jsfiddle.net/V92Gn/3899มันพยายามค้นหาวิธีแก้ปัญหาผ่านการกลายพันธุ์แบบสุ่ม มันจะไม่หยุดหากพบคำตอบ "ถูกต้อง" แต่สามารถหาวิธีแก้ไขปัญหาที่ถูกต้องได้เร็วกว่าคำตอบด้านล่าง
styletron

คำตอบ:


11

Pyth, 57 51 49 ไบต์

L.T.e+*]Ykbbsef!s.AMs.:R3ssmyBdsm_BdCBcTQsD^U2^Q2

เช่นเดียวกับโซลูชัน CJam ของ @ PeterTaylor นี่คือแรงเดรัจฉานดังนั้นจึงทำงานใน O (n 2 2 n 2 ) ล่ามออนไลน์ไม่เสร็จภายในหนึ่งนาทีสำหรับ n = 4

ลองที่นี่เพื่อ N <4

ลองใช้ฟังก์ชั่นเส้นทแยงมุม

L.T.e+*]Ykbb         y(b): diagonals of b (with some trailing [])
s e                  sum of the last (with most ones) array such that
f                    filter lambda T:
 ! s .AM                none of the 3 element sublists are all ones               
   s .:R3               all 3 element sublists
   s s                  flatten
   myBd                 add the diagonals
   sm_B d               add the vertically flipped array and transpose
   CBcTQ                array shaped into Q by Q square, and its transpose
 sD ^U2 ^Q2             all binary arrays of length Q^2 sorted by sum

13

CJam ( 58 56 ไบต์)

2q~:Xm*{7Yb#W=}:F,Xm*{ee{~0a@*\+}%zS*F},_Wf%:z&Mf*1fb:e>

มันช้าอย่างไม่น่าเชื่อและใช้หน่วยความจำจำนวนมาก แต่นั่นก็คือสำหรับคุณ

การผ่า

2q~:Xm*        e# Read input into X and find Cartesian product {0,1}^X
{7Yb#W=}:F,    e# Filter with a predicate F which rejects arrays with a 111
Xm*            e# Take the Cartesian product possible_rows^X to get possible grids
{              e# Filter out grids with an anti-diagonal 111 by...
  ee{~0a@*\+}% e#   prepending [0]*i to the ith row
  zS*F         e#   transposing, joining on a non-1, and applying F
},
_Wf%:z         e# Copy the filtered arrays and map a 90 degree rotation
&              e# Intersect. The rotation maps horizontal to vertical and
               e# anti-diagonal to diagonal, so this gets down to valid grids
Mf*            e# Flatten each grid
1fb            e# Count its 1s
:e>            e# Select the maximum

Θ(aX)a1.83928675...Θ(aX2)Θ(aX4) )


O(Xa3X)

public class A181018 {
    public static void main(String[] args) {
        for (int i = 1; i < 14; i++) {
            System.out.format("%d:\t%d\n", i, calc(i));
        }
    }

    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;
    }
}

วิธีการที่มีประสิทธิภาพทำงานในอะไร?
lirtosiast

@ThomasKwa โอ้มันยังคงเป็นเลขยกกำลัง แต่ฉันคิดว่ามันสมเหตุสมผลที่จะเรียกมันว่ามีประสิทธิภาพเพราะมันทำให้ฉันสามารถขยายลำดับ OEIS ได้ด้วย 3 คำ
Peter Taylor

@ThomasKwa จะแม่นยำก็ที่O(n a^n) a ~= 5.518
Peter Taylor

4

C, 460 456 410 407 362 351 318 ไบต์

นี่เป็นคำตอบที่ไม่ดีจริงๆ มันเป็นเรื่องเหลือเชื่อวิธีการบังคับเดรัจฉานช้าฉันพยายามตีกอล์ฟเพิ่มอีกนิดโดยการรวมforลูป

#define r return
#define d(x,y)b[x]*b[x+y]*b[x+2*(y)]
n,*b;s(i){for(;i<n*(n-2);++i)if(d(i%(n-2)+i/(n-2)*n,1)+d(i,n)+(i%n<n-2&&d(i,n+1)+d(i+2,n-1)))r 1;r 0;}t(x,c,l,f){if(s(0))r 0;b[x]++;if(x==n*n-1)r c+!s(0);l=t(x+1,c+1);b[x]--;f=t(x+1,c);r l>f?l:f;}main(c,v)char**v;{n=atol(v[1]);b=calloc(n*n,4);printf("%d",t(0,0));}

กรณีทดสอบ

$ ./a.out 1
1$ ./a.out 2
4$ ./a.out 3
6$ ./a.out 4
9$ ./a.out 5
16$

Ungolfed

n,*b; /* board size, board */

s(i) /* Is the board solved? */
{
    for(;i<n*(n-2);++i) /* Iterate through the board */
            if(b[i%(n-2)+i/(n-2)*n]&&b[i%(n-2)+i/(n-2)*n+1]&&b[i%(n-2)+i/(n-2)*n+2] /* Check for horizontal tic-tac-toe */
                    || b[i] && b[i+n] && b[i+2*n] /* Check for vertical tic-tac-toe */
                    || (i%n<n-2
                            && (b[i] &&b [i+n+1] && b[i+2*n+2] /* Check for diagonal tic-tac-toe */
                                    || b[i+2*n] && b[i+n+1] && b[i+2]))) /* Check for reverse diagonal tic-tac-toe */
                    return 1;
    return 0;
}

t(x,c,l,f) /* Try a move at the given index */
{
    if(s(0)) /* If board is solved, this is not a viable path */
            return 0;
    b[x]++;
    if(x==n*n-1) /* If we've reached the last square, return the count */
            return c+!s(0);

    /* Try it with the cross */
    l=t(x+1,c+1);

    /* And try it without */
    b[x]--;
    f=t(x+1,c);

    /* Return the better result of the two */
    return l>f?l:f;
}

main(c,v)
char**v;
{
    n=atol(v[1]); /* Get the board size */
    b=calloc(n*n,4); /* Allocate a board */
    printf("%d",t(0,0)); /* Print the result */
}

แก้ไข: ประกาศตัวแปร int เป็นพารามิเตอร์ที่ไม่ได้ใช้ ลบพิกัด y เพียงใช้ดัชนี ย้ายตัวแปรรายการพารามิเตอร์มากกว่าโลกแก้ไขพารามิเตอร์ที่ไม่จำเป็นผ่านไปs(); รวมสำหรับลูปลบวงเล็บที่ไม่จำเป็น แทนที่&&ด้วย*, ||ด้วย+; macro-ify การตรวจสอบ 3-in-a-row


มันช้าแค่ไหน?
Loovjo

@ Loovjo พยายามบนพีซีของฉันด้วยการเปลี่ยนแปลงเล็กน้อยเพื่อให้เร็วขึ้น 15ms สำหรับ n = 5, 12 วินาทีสำหรับ n = 6 (อินพุต +1, เวลา * 800)!
edc65

@ edc65 นั่นเป็นประสบการณ์ของฉัน อะไรที่มากกว่า 5 ของประสิทธิภาพก็ช้าลงอย่างมาก ฉันไม่ได้กังวลกับการลองอินพุตมากกว่า 6
Cole Cameron

ฉันเริ่มต้นด้วย 7 เมื่อฉันโพสต์ความคิดเห็นของฉัน เราจะเห็น
edc65

คุณสามารถบีบออกมาเป็นตัวอักษรอีกไม่กี่กับ#define d(x,y)b[x]*b[x+y]*b[x+y+y]; โดยการเปลี่ยนจุดเริ่มต้นของsเป็นs(i,m){for(m=n-2;และแทนที่อินสแตนซ์ทั้งหมดของn-2; และโดยการเปลี่ยนb[x]++ไปb[x++]++แล้วแทนที่x==n*n-1ด้วยx==n*n, x+1มีxและมีx x-1
Peter Taylor

4

C 263 264 283 309

แก้ไขบันทึกไม่กี่ไบต์ขอบคุณ @Peter Taylor - น้อยกว่าที่ฉันคาดไว้ จากนั้น 2 ไบต์ใช้ในการจัดสรรหน่วยความจำเพิ่มเติมตอนนี้ฉันสามารถลองขนาดที่ใหญ่ขึ้น แต่มันใช้เวลานานมาก

หมายเหตุในขณะที่เพิ่มคำอธิบายฉันพบว่าฉันกำลังสูญเสียจำนวนไบต์ที่เก็บกริดในอาเรย์ R - เพื่อให้คุณสามารถเห็นวิธีแก้ปัญหาที่พบ ... ไม่ขอความท้าทายนี้ !!
ฉันลบมันในเวอร์ชัน golfed

โปรแกรม C golfed ที่สามารถหาคำตอบได้จริงสำหรับ n = 1..10 ในเวลาที่เหมาะสม

s,k,n,V[9999],B[9999],i,b;K(l,w,u,t,i){for(t=u&t|u*2&t*4|u/2&t/4,--l; i--;)V[i]&t||(b=B[i]+w,l?b+(n+2)/3*2*l>s&&K(l,b,V[i],u,k):b>s?s=b:0);}main(v){for(scanf("%d",&n);(v=V[i]*2)<1<<n;v%8<6?B[V[k]=v+1,k++]=b+1:0)V[k]=v,b=B[k++]=B[i++];K(n,0,0,0,k);printf("%d",s);}

การทดสอบของฉัน:

7 -> 26 ใน 10 วินาที
8 -> 36 ใน 18 วินาที
9 -> 42 ใน 1162 วินาที

หักกอล์ฟและพยายามอธิบาย

#include <stdio.h>

int n, // the grid size
    s, // the result
    k, // the number of valid rows 
    V[9999], // the list of valid rows (0..to k-1) as bitmasks
    B[9999], // the list of 'weight' for each valid rows (number of set bits)
    R[99],  // the grid as an array of indices pointing to bitmask in V
    b,i; // int globals set to 0, to avoid int declaration inside functions

// recursive function to fill the grid
int K(
  int l, // number of rows filled so far == index of row to add
  int w, // number of crosses so far
  int u, // bit mask of the preceding line (V[r[l-1]])
  int t, // bit mask of the preceding preceding line (V[r[l-2]])
  int i) // the loop variables, init to k at each call, will go down to 0
{
  // build a bit mask to check the next line 
  // with the limit of 3 crosses we need to check the 2 preceding rows
  t = u&t | u*2 & t*4 | u/2 & t/4; 
  for (; i--; )// loop on the k possibile values in V
  {
    R[l] = i; // store current row in R
    b = B[i] + w; // new number of crosses if this row is accepted
    if ((V[i] & t) == 0) // check if there are not 3 adjacent crosses
      // then check if the score that we can reach from this point
      // adding the missing rows can eventually be greater
      // than the current max score stored in s
      if (b + (n + 2) / 3 * 2 * (n - l - 1) > s)
        if (l > n-2) // if at last row
          s = b > s ? b : s; // update the max score
        else  // not the last row
          K(l + 1, b, V[i], u, k); // recursive call, try to add another row
  }
}

int main(int j)
{
  scanf("%d", &n);

  // find all valid rows - not having more than 2 adjacent crosses
  // put valid rows in array V
  // for each valid row found, store the cross number in array B
  // the number of valid rows will be in k
  for (; i<1 << n; V[k] = i++, k += !b) // i is global and start at 0
    for (b = B[k] = 0, j = i; j; j /= 2) 
      b = ~(j | -8) ? b : 1, B[k] += j & 1;
  K(0,0,0,0,k); // call recursive function to find the max score
  printf("%d\n", s);
}

นี่เป็นหลักเหมือนกับโปรแกรม Java ของฉัน แต่ลึกก่อนมากกว่าความกว้างก่อน ฉันคิดว่าคุณควรจะสามารถบันทึกอย่างน้อยหนึ่งโหลตัวละครโดยbuildRowsวิธีการของฉัน; อาจจะมากถึง 20 ถ้าfor(scanf("%d",&n);(v=2*V[i++])<1<<n;v%8<6&&V[++j]=v+1)v&&V[++j]=v;ถูกต้อง (ฉันไม่สามารถเข้าถึงคอมไพเลอร์ C ได้ในขณะนี้)
Peter Taylor

1
@PeterTaylor ฉันจะให้มันดู ... เพียงแค่คำว่าtribonacciกำลังทำให้ฉันกลัว
edc65

ฮาร์ดโค้ดของคุณ999หมายความว่าคุณต้องการที่จะไม่สนใจส่วนนั้น แม้ว่าบางทีคุณควรทำให้มันไม่ได้เข้ารหัสยากจริงๆดังนั้นโดยหลักการแล้วคุณสามารถจัดการอินพุตที่มีขนาดใหญ่กว่า 11 หรือ 12 ได้
Peter Taylor

@ PeterTaylor มันจะทำงานได้ดีถ้าฉันมี. bitCount วิธีการใน C เพื่อนับบิต แต่ในเฟสแรกนั้นฉันจะเปรียบเทียบจำนวนบิตใน B ไม่เพียง แต่บิตมาสก์ใน V
edc65

2

Ruby, 263 ไบต์

นี่เป็นวิธีแก้ปัญหาที่ดุร้ายและเผชิญหน้ากับปัญหาเดียวกันกับคำตอบ C ของ Cole Cameron แต่ก็ช้ากว่านี้เพราะเป็นทับทิมและไม่ใช่ C. แต่เดี๋ยวก่อนมันสั้นกว่า

c=->(b){b.transpose.all?{|a|/111/!~a*''}}
m=->(b,j=0){b[j/N][j%N]=1
x,*o=b.map.with_index,0
c[b]&&c[b.transpose]&&c[x.map{|a,i|o*(N-i)+a+o*i}]&&c[x.map{|a,i|o*i+a+o*(N-i)}]?(((j+1)...N*N).map{|i|m[b.map(&:dup),i]}.max||0)+1:0}
N=$*[0].to_i
p m[N.times.map{[0]*N}]

กรณีทดสอบ

$ ruby A181018.rb 1
1
$ ruby A181018.rb 2
4
$ ruby A181018.rb 3
6
$ ruby A181018.rb 4
9
$ ruby A181018.rb 5
16

Ungolfed

def check_columns(board)
  board.transpose.all? do |column|
    !column.join('').match(/111/)
  end
end

def check_if_unsolved(board)
  check_columns(board) && # check columns
    check_columns(board.transpose) && # check rows
    check_columns(board.map.with_index.map { |row, i| [0] * (N - i) + row + [0] * i }) && # check decending diagonals
    check_columns(board.map.with_index.map { |row, i| [0] * i + row + [0] * (N - i) }) # check ascending diagonals
end

def maximum_crosses_to_place(board, index=0)
  board[index / N][index % N] = 1 # set cross at index
  if check_if_unsolved(board)
    crosses = ((index + 1)...(N*N)).map do |i|
      maximum_crosses_to_place(board.map(&:dup), i)
    end
    maximum_crosses = crosses.max || 0
    maximum_crosses + 1
  else
    0
  end
end

N = ARGV[0].to_i
matrix_of_zeros = N.times.map{ [0]*N }

puts maximum_crosses_to_place(matrix_of_zeros)

1

Haskell, 143 ไบต์

ในบางวิธีนี้ไม่ได้ทำ แต่ฉันสนุกไปเลย:

  • เนื่องจากการตรวจสอบรูปแบบ "ชนะ" ในแนวนอนจึงไม่ถูกต้องหากนำไปใช้กับแถวที่ต่างกันอินพุตของ N <3 จึงคืนค่า 0
  • "อาร์เรย์" เป็นจำนวนเต็มแยกออกเป็นบิตดังนั้นนับได้ง่าย
  • ((i! x) y) ให้ ith บิตของ x คูณ y โดยที่ดัชนีลบส่งกลับ 0 ดังนั้นช่วงสามารถคงที่ (ไม่มีการตรวจสอบขอบเขต) และวงเล็บน้อยเมื่อถูกล่ามโซ่
  • เนื่องจากไม่ได้ตรวจสอบขอบเขตมันจึงตรวจสอบรูปแบบ 81 * 4 = 324 สำหรับทุกค่าสูงสุดที่เป็นไปได้ซึ่งนำไปสู่ ​​N = 3 ใช้แล็ปท็อปของฉัน 9 วินาทีและ N = 5 ใช้เวลานานเกินไปที่ฉันจะปล่อยให้มันเสร็จ
  • ตรรกะบูลีนบน 1/0 ใช้สำหรับ T / F เพื่อประหยัดเนื้อที่ตัวอย่างเช่น (*) คือ &&, (1-x) คือ (ไม่ใช่ x) เป็นต้น
  • เนื่องจากตรวจสอบจำนวนเต็มแทนอาร์เรย์ (div p1 L) == (div p2 L) เพื่อให้แน่ใจว่ารูปแบบไม่ได้ถูกตรวจสอบในแถวต่างๆโดยที่ L คือความยาวของแถวและ p1, p2 เป็นตำแหน่ง
  • ค่าสูงสุดที่เป็นไปได้คือ Hamming Weight

นี่คือรหัส:

r=[0..81]
(%)=div
s=sum
i!x|i<0=(*0)|0<1=(*mod(x%(2^i))2)
f l=maximum[s[i!x$1-s[s[1#2,l#(l+l),(l+1)#(l+l+2),(1-l)#(2-l-l)]|p<-r,let  a#b=p!x$(p+a)!x$(p+b)!x$s[1|p%l==(p+mod b l)%l]]|i<-r]|x<-[0..2^l^2]]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.