ปลูกต้นไม้ในสวนสาธารณะ - เร็วที่สุดเท่าที่จะทำได้!


20

ความท้าทายนี้ได้รับแรงบันดาลใจจากแอพนี้ กรณีทดสอบถูกยืมมาจากแอพนั้น


นี่คือความท้าทายวัตถุประสงค์เพื่อแก้กรณีทดสอบที่ใหญ่ที่สุดในเวลาน้อยที่สุด มีกรณีทดสอบขนาดเล็กกว่าเล็กน้อยเพื่อให้ผู้คนสามารถทดสอบอัลกอริทึมของพวกเขาได้เร็วขึ้น


คุณจะได้รับตารางตารางการป้อนข้อมูลของขนาดn โดย nที่9 <= n <= 12 ตารางนี้จะแบ่งออกเป็นพื้นที่nซึ่งเซลล์ของแต่ละพื้นที่มีตัวระบุเฉพาะ (ฉันจะใช้ตัวอักษรตัวพิมพ์เล็กจากalในข้อความที่นี่ แต่คุณอาจเลือกสิ่งที่คุณต้องการเช่นจำนวนเต็ม1-12 ) .

อินพุตอาจมีลักษณะดังนี้ (รูปแบบอินพุตเสริม):

aabbbbbcc
adddbbbcc
adeeecccc
adddefgcc
hhhdifggg
hdddifffg
hhhiifffg
hihiifffg
iiiiiiggg

หรือง่ายต่อการมองเห็น:

ป้อนคำอธิบายรูปภาพที่นี่

ท้าทาย:

คุณต้องวางต้นไม้2 * nในสวนนี้ตามกฎต่อไปนี้:

  • จะต้องมี2ต้นต่อคอลัมน์และ2ต้นต่อแถว
  • พื้นที่ทั้งหมดจะต้องมีต้นไม้2ต้น
  • ไม่มีต้นไม้ใดที่สามารถติดกับต้นไม้ต้นอื่นได้ทั้งแนวตั้งแนวนอนหรือแนวทแยงมุม

วิธีแก้ปัญหาสำหรับเค้าโครงด้านบนคือ:

ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุ: มีเพียงทางออกเดียวสำหรับปริศนาแต่ละตัว

กฎเพิ่มเติม:

  • รูปแบบอินพุตและเอาต์พุตเป็นทางเลือก
    • ตัวอย่างเช่นผลลัพธ์อาจเป็นรายการของดัชนีกริดที่มี1/0 เพื่อระบุว่ามีต้นไม้อยู่ในตำแหน่งนั้นหรือเป็นเวอร์ชั่นที่ได้รับการแก้ไขของอินพุตซึ่งมีการระบุต้นไม้
  • เวลาดำเนินการจะต้องกำหนดไว้ล่วงหน้า
  • โปรแกรมจะต้องเสร็จสิ้นภายใน 1 นาทีที่คอมพิวเตอร์ของ @ isaacg
    • รายละเอียด: 4 CPU, i5-4300U CPU @ 1.9 GHz, 7.5G of RAM
  • ในกรณีที่โปรแกรมของคุณไม่สามารถแก้กรณีทดสอบที่ใหญ่ที่สุดสองรายการในหนึ่งนาทีจากนั้นเวลาสำหรับกรณีที่ใหญ่ที่สุดอันดับสอง ( n = 11 ) จะเป็นคะแนนของคุณ คุณจะแพ้การแก้ปัญหาที่แก้ไขกรณีที่ใหญ่ที่สุด

กรณีทดสอบ:

ฉันอาจแก้ไขรายการนี้หากดูเหมือนว่าจะมีการปรับแต่งการส่งเพื่อให้เหมาะสมกับกรณีทดสอบเหล่านี้

12 ต่อ 12 :

--- Input ---
aaaaabccccdd
aaaaabccccdd
aaaaabbbbddd
eeeafffgbghh
eeaafffgbghh
eefffffggghh
eeefijffghhh
iieiijjjjkhh
iiiiijjjjkhk
lljjjjjjjkkk
llllllkkkkkk
llllllkkkkkk
--- Solution ---
aaaaabcccCdD
aaaaaBcCccdd
aAaaabbbbdDd
eeeaffFgBghh
eeAaFffgbghh
eefffffGgGhh
EeefijffghhH
iiEiIjjjjkhh
IiiiijjjjkHk
lljJjJjjjkkk
lLllllkkKkkk
lllLllKkkkkk

11 ต่อ 11 :

--- Input ---
aaaaaaabbcc
adddabbbbcc
edddbbbbbbc
eddddbbbbbb
effffggghhh
effffgghhii
eefffjjhhii
eeeejjjhhii
eeejjjjkiii
jjjjjjkkiii
jjjjjkkkiii
--- Solution ---
aaAaaaabbCc
adddAbBbbcc
eDddbbbbbbC
eddDdBbbbbb
effffggGhHh
eFfffGghhii
eefFfjjhHii
EeeejjjhhiI
eeEjjjjKiii
JjjjJjkkiii
jjjjjkKkIii

10 โดย 10

--- Input ---
aaaaabccdd
aeaabbbccd
aeaabfbgcd
eeeaafggcd
eeeaafghcd
eeeiifghcd
ieiiigghcd
iiijighhcd
jjjjighhcd
jjjggghhdd
--- Solution ---
aaAaabccdD
aeaaBbBccd
aEaabfbgcD
eeeaaFgGcd
eEeAafghcd
eeeiiFghCd
IeiIigghcd
iiijigHhCd
JjJjighhcd
jjjgGghHdd

9 โดย 9

--- Input ---
aabbbbbcc
adddbbbcc
adeeecccc
adddefgcc
hhhdifggg
hdddifffg
hhhiifffg
hihiifffg
iiiiiiggg
--- Solution ---
aAbBbbbcc
adddbbBcC
adEeEcccc
AdddefgCc
hhhDiFggg
hDddifffG
hhhiIfFfg
HiHiifffg
iiiiiIgGg
--- Input ---
aaabbbccc
aaaabbccc
aaaddbcce
ffddddcce
ffffddeee
fgffdheee
fggfhhhee
iggggheee
iiigggggg
--- Solution ---
aaAbBbccc
AaaabbcCc
aaaDdBcce
fFddddcCe
fffFdDeee
fGffdheeE
fggfHhHee
IggggheeE
iiIgggGgg

"รูปแบบอินพุตและเอาต์พุตเป็นตัวเลือก แต่ควรเหมือนกัน" หมายความว่าอย่างไร ฉันไม่สามารถส่งออกรายการที่มี 1s และ 0s สำหรับต้นไม้และไม่ใช่ต้นไม้โดยไม่สนใจเกี่ยวกับการแสดงผลพื้นที่ได้หรือไม่
เสียชีวิต

@ กระชับแก้ไข ฉันคิดว่าการแสดงรายการดัชนีหรือกริดด้วย 1/0 ตามที่คุณแนะนำเป็นความคิดที่ดี
Stewie Griffin

1
ข้อมูล (ถ้าฉันคำนวณอย่างถูกต้อง): มีการกำหนดค่า 3647375398569086976 ที่จะนำต้นไม้ 24 ต้นในตาราง 12 * 12 ที่ตอบสนองเท่านั้น (1): There shall be exactly 2 trees per column, and 2 trees per rowดังนั้นจึงเป็นไปไม่ได้
user202729

"ไม่ควรเป็นปัญหาใหญ่" : ฉันคิดว่าเป็นการส่วนตัว การใช้งานปัจจุบันของฉันแก้กรณีทดสอบครั้งแรกใน ~ 150ms และที่ 3 ใน 5 วินาที แต่ล้มเหลวในการแก้ไขกรณีสุดท้าย (ซึ่งเป็น 'เพียง' 11x11) ในเวลาที่เหมาะสม มันอาจจะต้องใช้การตัดต่อที่ก้าวร้าวมากขึ้นและดังนั้นจึงมีรหัสเพิ่มเติมจำนวนมาก - ให้เสร็จสมบูรณ์ภายใน 1 นาที
Arnauld

1
@Arnauld ฉันเปลี่ยนค่าสูงสุดเป็น 11 เนื่องจากเป็นกรณีทดสอบที่ใหญ่ที่สุด คุณสามารถโพสต์วิธีแก้ปัญหาของคุณ (เป็นความถูกต้องส่งแข่งขัน) แต่จะไม่ชนะถ้ามีคนโพสต์โซลูชั่นที่แก้กรณีทดสอบทั้งหมดโดยไม่คำนึงถึงความยาวรหัส ยุติธรรม?
Stewie Griffin

คำตอบ:


7

JavaScript (ES6), 271 ไบต์

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

f=(a,p=0,r=[S=y=0],w=a.length)=>a.some((R,y)=>a.some((_,x)=>r[y]>>x&1&&(o[k=R[x]]=-~o[k])>2),o=[])?0:y<w?[...Array(1<<w)].some((_,n)=>(k=n^(x=n&-n))<=x*2|k&-k^k|n&(p|p/2|p*2)||r.some((A,i)=>r.some((B,j)=>A&B&n&&i<y&j<i))?0:(w=r[y],f(a,r[y++]=n,r),r[--y]=w,S))&&S:S=[...r]

จัดรูปแบบและแสดงความคิดเห็น

f = (                                           // given:
  a,                                            //   - a = input matrix
  p = 0,                                        //   - p = previous bitmask
  r = [                                         //   - r = array of tree bitmasks
        S = y = 0 ],                            //   - S = solution / y = current row
  w = a.length                                  //   - w = width of matrix
) =>                                            //
  a.some((R, y) => a.some((_, x) =>             // if there's at least one area with more
    r[y] >> x & 1 && (o[k = R[x]] = -~o[k]) > 2 // than two trees:
  ), o = []) ?                                  //
    0                                           //   abort right away
  :                                             // else:
    y < w ?                                     //   if we haven't reached the last row:
      [...Array(1 << w)].some((_, n) =>         //     for each possible bitmask n:
        (k = n ^ (x = n & -n)) <= x * 2 |       //       if the bitmask does not consist of
        k & - k ^ k |                           //       exactly two non-consecutive bits,
        n & (p | p / 2 | p * 2) ||              //       or is colliding with the previous
        r.some((A, i) => r.some((B, j) =>       //       bitmask, or generates more than two
          A & B & n && i < y & j < i            //       trees per column:
        )) ?                                    //
          0                                     //         yield 0
        :                                       //       else:
          (                                     //
            w = r[y],                           //         save the previous bitmask
            f(a, r[y++] = n, r),                //         recursive call with the new one
            r[--y] = w,                         //         restore the previous bitmask
            S                                   //         yield S
          )                                     //
      ) && S                                    //     end of some(): return false or S
    :                                           //   else:
      S = [...r]                                //     this is a solution: save a copy in S

กรณีทดสอบ

ตัวอย่างนี้มีฟังก์ชันเพิ่มเติมเพื่อแสดงผลลัพธ์ในรูปแบบที่อ่านได้ง่ายขึ้น ช้าเกินไปที่จะแก้กรณีทดสอบสุดท้าย

คาดว่าจะใช้งานได้: ~ 5 วินาที


หมายเหตุของ OP: การส่งนี้เกิดขึ้นเมื่อความท้าทายเป็นความท้าทายของรหัสกอล์ฟ ดังนั้นจึงใช้ได้อย่างสมบูรณ์แม้ว่าจะไม่ได้รับการปรับให้เหมาะกับเกณฑ์การชนะในปัจจุบัน!
Stewie Griffin

การจับเวลา: ใช้เวลาประมาณหนึ่งนาทีในวันที่ 11x11
isaacg

เรากำลังดองคุณอาจช่วยได้ คุณนึกถึงวิธีใดในการสร้างอินสแตนซ์ปริศนาที่ไม่น่าสนใจขนาดใหญ่ได้ไหม?
isaacg

7

C, เวลาอย่างเป็นทางการ: 5ms สำหรับ 12x12

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <omp.h>

#define valT char
#define posT int

#ifndef _OPENMP
#  warning Building without OpenMP support
#  define omp_get_max_threads() 1
#  define omp_get_num_threads() 1
#  define omp_get_thread_num() 0
#endif

#define MIN_THREADED_SIZE 11

static void complete(posT n, valT *workspace) {
    const posT s = n * 3 + 2;

    const valT *regions = workspace;
    valT *output = &workspace[n*2+1];

    for(posT y = 0; y < n; ++ y) {
        for(posT x = 0; x < n; ++ x) {
//          putchar(output[y*s+x] ? '*' : '-');
            putchar(regions[y*s+x] + (output[y*s+x] ? 'A' : 'a'));
        }
        putchar('\n');
    }

    _Exit(0);
}

static void solveB(const posT n, valT *workspace, valT *pops, const posT y) {
    const posT s = n * 3 + 2;

    const valT *regions = workspace;
    const valT *remaining = &workspace[n];
    valT *output = &workspace[n*2+1];

    for(posT r = 0; r < n; ++ r) {
        if(pops[r] + remaining[r] < 2) {
            return;
        }
    }

    for(posT t1 = 0; t1 < n - 2; ++ t1) {
        posT r1 = regions[t1];
        if(output[t1+1-s]) {
            t1 += 2;
            continue;
        }
        if(output[t1-s]) {
            ++ t1;
            continue;
        }
        if((pops[t1+n] | pops[r1]) & 2 || output[t1-1-s]) {
            continue;
        }
        output[t1] = 1;
        ++ pops[t1+n];
        ++ pops[r1];
        for(posT t2 = t1 + 2; t2 < n; ++ t2) {
            posT r2 = regions[t2];
            if(output[t2+1-s]) {
                t2 += 2;
                continue;
            }
            if(output[t2-s]) {
                ++ t2;
                continue;
            }
            if((pops[t2+n] | pops[r2]) & 2 || output[t2-1-s]) {
                continue;
            }
            output[t2] = 1;
            ++ pops[t2+n];
            ++ pops[r2];
            if(y == 0) {
                complete(n, &workspace[-s*(n-1)]);
            }
            solveB(n, &workspace[s], pops, y - 1);
            output[t2] = 0;
            -- pops[t2+n];
            -- pops[r2];
        }
        output[t1] = 0;
        -- pops[t1+n];
        -- pops[r1];
    }
}

static void solve(const posT n, valT *workspace) {
    const posT s = n * 3 + 2;

    valT *regions = workspace;
    valT *remaining = &workspace[n];
    valT *pops = &workspace[n*s];
//  memset(&remaining[n*s], 0, n * sizeof(valT));

    for(posT y = n; (y --) > 0;) {
        memcpy(&remaining[y*s], &remaining[(y+1)*s], n * sizeof(valT));
        for(posT x = 0; x < n; ++ x) {
            valT r = regions[y*s+x];
            valT *c = &remaining[y*s+r];
            valT *b = &pops[r*3];
            if(*c == 0) {
                *c = 1;
                b[0] = y - 1;
                b[1] = x - 1;
                b[2] = x + 1;
            } else if(x < b[1] || x > b[2] || y < b[0]) {
                *c = 2;
            } else {
                b[1] = b[1] > (x - 1) ? b[1] : (x - 1);
                b[2] = b[2] < (x + 1) ? b[2] : (x + 1);
            }
        }
//      memset(&output[y*s], 0, (n+1) * sizeof(valT));
    }
    memset(pops, 0, n * 2 * sizeof(valT));

    posT sz = (n + 1) * s + n * 3;
    if(n >= MIN_THREADED_SIZE) {
        for(posT i = 1; i < omp_get_max_threads(); ++ i) {
            memcpy(&workspace[i*sz], workspace, sz * sizeof(valT));
        }
    }

#pragma omp parallel for if (n >= MIN_THREADED_SIZE)
    for(posT t1 = 0; t1 < n - 2; ++ t1) {
        valT *workspace2 = &workspace[omp_get_thread_num()*sz];
        valT *regions = workspace2;
        valT *output = &workspace2[n*2+1];
        valT *pops = &workspace2[n*s];

        posT r1 = regions[t1];
        output[t1] = pops[t1+n] = pops[r1] = 1;
        for(posT t2 = t1 + 2; t2 < n; ++ t2) {
            posT r2 = regions[t2];
            output[t2] = pops[t2+n] = 1;
            ++ pops[r2];
            solveB(n, &regions[s], pops, n - 2);
            output[t2] = pops[t2+n] = 0;
            -- pops[r2];
        }
        output[t1] = pops[t1+n] = pops[r1] = 0;
    }
}

int main(int argc, const char *const *argv) {
    if(argc < 2) {
        fprintf(stderr, "Usage: %s 'grid-here'\n", argv[0]);
        return 1;
    }

    const char *input = argv[1];
    const posT n = strchr(input, '\n') - input;
    const posT s = n * 3 + 2;

    posT sz = (n + 1) * s + n * 3;
    posT threads = (n >= MIN_THREADED_SIZE) ? omp_get_max_threads() : 1;
    valT *workspace = (valT*) calloc(sz * threads, sizeof(valT));
    valT *regions = workspace;

    for(posT y = 0; y < n; ++ y) {
        for(posT x = 0; x < n; ++ x) {
            regions[y*s+x] = input[y*(n+1)+x] - 'a';
        }
    }

    solve(n, workspace);

    fprintf(stderr, "Failed to solve grid\n");
    return 1;
}

คอมไพล์ด้วย GCC 7 โดยใช้-O3และตั้ง-fopenmpค่าสถานะ ควรมีผลลัพธ์ที่คล้ายกันใน GCC ทุกรุ่นที่ติดตั้ง OpenMP

gcc-7 Trees.c -O3 -fopenmp -o Trees

รูปแบบอินพุตและเอาต์พุตตามที่กำหนดในคำถาม

ในเครื่องของฉันใช้เวลา0.009s 0.008s 0.005s สำหรับตัวอย่าง 12x12 และ0.022 วินาที 0.020 วินาที 0.019s เพื่อเรียกใช้ตัวอย่างทั้งหมด บนเครื่องเบนช์มาร์ก isaacg รายงาน 5ms สำหรับตัวอย่าง 12x12 โดยใช้รหัสต้นฉบับ (แบบไม่มีเธรด)

การใช้งาน:

./Trees 'aaabbbccc
aaaabbccc
aaaddbcce
ffddddcce
ffffddeee
fgffdheee
fggfhhhee
iggggheee
iiigggggg'

เป็นเพียงเครื่องมือแก้ปัญหาแบบเดรัจฉานกำลังทำงานอยู่ในแต่ละแถว มันวิ่งด้วยความเร็วที่ดีโดยการรับรู้สถานการณ์ที่เป็นไปไม่ได้เร็ว (เช่นไม่มีเซลล์พื้นที่ที่เหลือ แต่น้อยกว่า 2 ต้นในภูมิภาค)

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

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


การจับเวลาอย่างเป็นทางการ: 5ms สำหรับ 12x12 หากใครเข้ามาใกล้เราจะต้องใช้กรณีทดสอบที่ใหญ่กว่า
isaacg

เรากำลังดองอยู่บางทีคุณอาจช่วยได้ คุณนึกถึงวิธีใดในการสร้างอินสแตนซ์ปริศนาที่ไม่น่าสนใจขนาดใหญ่หรือ
isaacg

@isaacg จากตัวอย่างที่แสดงให้เห็นดูเหมือนว่ากริดดั้งเดิมถูกสร้างขึ้นโดยการวางต้นไม้ก่อน (ในรูปแบบอัศวินที่มีการเปลี่ยนแปลงเล็กน้อยในตัวอย่างนั้น แต่ฉันเดาว่ารูปแบบใด ๆ ที่มี 2 ต้นต่อแถวและคอลัมน์จะทำงาน) เพื่อให้แต่ละภูมิภาคมีต้นไม้ 2 ต้น ดูเหมือนว่าควรเป็นวิธีที่ง่ายพอสำหรับมนุษย์ที่จะติดตามกริดขนาดใหญ่โดยพลการ
เดฟ

ในความเป็นจริงแล้วดูอีกครั้งไม่ใช่รูปแบบอัศวินที่มีการเปลี่ยนแปลงเล็กน้อย แต่รูปแบบการตัดที่ต้นไม้แต่ละต้นถูกชดเชย (1,2) จากก่อนหน้านี้ เมื่อคุณมีรูปแบบแล้วคุณสามารถเปลี่ยนแถวและคอลัมน์เพื่อสร้างโซลูชันที่มีโครงสร้างน้อยลงตราบใดที่มันไม่ทิ้งต้นไม้ไว้ติดกัน
เดฟ

5

Java (OpenJDK 8) , เวลาที่เป็นทางการ: 1.2s บน 12x12

แก้ไข: ไม่มีรหัสกอล์ฟอีกต่อไป

import java.util.*;

// Callable method, takes an int[][] and modifies it
static void f(int[][] areas){
    List<List<BitSet>> areaBitSets = new ArrayList<>();
    List<List<BitSet>> areaTreeBitSets = new ArrayList<>();
    for(int i = 0; i < areas.length; i++){
        areaBitSets.add(new ArrayList<BitSet>());
        areaTreeBitSets.add(new ArrayList<BitSet>());
    }

    // Add a bitset to our list representing each possible square, grouped by area
    for(int i=0; i < areas.length; i++){
        for(int j=0; j < areas.length; j++){
            BitSet b = new BitSet();
            b.set(i*areas.length + j);
            areaBitSets.get(areas[i][j]).add(b);
        }
    }

    // Fold each set onto itself so each area bitset has two trees
    for(int i=0; i < areas.length; i++){
        for(int j=0; j<areaBitSets.get(i).size()-1; j++){
            for(int k=j+1; k <areaBitSets.get(i).size(); k++){
                if(canFoldTogether(areaBitSets.get(i).get(j),areaBitSets.get(i).get(k), areas.length)){
                    BitSet b = (BitSet)areaBitSets.get(i).get(j).clone();
                    b.or(areaBitSets.get(i).get(k));
                    areaTreeBitSets.get(i).add(b);
                }
            }
        }
    }

    // Starting with area 0 add each area one at a time doing Cartesian products
    Queue<BitSet> currentPossibilities = new LinkedList<>();
    Queue<BitSet> futurePossibilities = new LinkedList<>();
    currentPossibilities.addAll(areaTreeBitSets.get(0));

    for(int i=1; i < areaTreeBitSets.size(); i++){
        while(!currentPossibilities.isEmpty()){
            BitSet b= (BitSet)currentPossibilities.poll().clone();

            for(BitSet c: areaTreeBitSets.get(i)){
                if(canFoldTogether(b,c,areas.length)){
                    BitSet d=(BitSet)b.clone();
                    d.or(c);
                    futurePossibilities.add(d);
                }
            }
        }
        currentPossibilities.addAll(futurePossibilities);
        futurePossibilities.clear();
    }

    // Get final output and modify the array
    BitSet b = currentPossibilities.poll();
    for(int i=0; i<areas.length*areas.length; i++){
        areas[i/areas.length][i%areas.length] = b.get(i)?1:0;
    }
}

// Helper method which determines whether combining two bitsets
// will still produce a valid output
static boolean canFoldTogether(BitSet a, BitSet b, int size){

    // See if there are trees too close to each other
    int c=-1;
    while((c=a.nextSetBit(c+1))>=0){
        int d=-1;
        while((d=b.nextSetBit(d+1))>=0){
            int r1=c/size;
            int r2=d/size;
            int c1=c%size;
            int c2=d%size;

            int rDifference = r1>r2 ? r1-r2 : r2-r1;
            int cDifference = c1>c2 ? c1-c2 : c2-c1;
            if(rDifference<2 && cDifference<2)
                return false;
        }
    }

    // Check for row and column cardinality
    BitSet f,g;
    for(int i=0; i<size; i++){
        f = new BitSet();
        f.set(i*size,(i+1)*size);
        g=(BitSet)f.clone();
        f.and(a);
        g.and(b);
        f.or(g);
        if(f.cardinality()>2){
            return false;
        }


        f=new BitSet();
        for(int j = 0; j<size; j++){
            f.set(j*size+i);
        }
        g=(BitSet)f.clone();
        f.and(a);
        g.and(b);
        f.or(g);
        if(f.cardinality()>2){
            return false;
        }
    }

    return true;
}

ลองออนไลน์!

ลิงก์ TIO ใช้สำหรับกรณีทดสอบ 12x12 TIO รายงาน 2.429s สำหรับเวลาทำงาน

รับอาร์เรย์จำนวนเต็มเป็นอินพุตและแก้ไขอาร์เรย์เพื่อให้มี 1s สำหรับ trees และ 0s สำหรับ non-trees

สิ่งนี้จะทำงานสำหรับการทดสอบทั้งหมด Testcase ที่ใหญ่ที่สุดทำงานบนเครื่องของฉันในเวลาไม่ถึงวินาทีแม้ว่าฉันจะมีเครื่องจักรที่ทรงพลังทีเดียว

รหัสทดสอบสำหรับ 12x12 สามารถแก้ไขได้สำหรับผู้อื่น

public static void main(String[] args){
    int[][] test = {{0,  0,  0,  0,  0,  1,  2,  2,  2,  2,  3,  3}, 
            {0,  0,  0,  0,  0,  1,  2,  2,  2,  2,  3,  3}, 
            {0,  0,  0,  0,  0,  1,  1,  1,  1,  3,  3,  3}, 
            {4,  4,  4,  0,  5,  5,  5,  6,  1,  6,  7,  7}, 
            {4,  4,  0,  0,  5,  5,  5,  6,  1,  6,  7,  7}, 
            {4,  4,  5,  5,  5,  5,  5,  6,  6,  6,  7,  7}, 
            {4,  4,  4,  5,  8,  9,  5,  5,  6,  7,  7,  7}, 
            {8,  8,  4,  8,  8,  9,  9,  9,  9,  10,  7,  7}, 
            {8,  8,  8,  8,  8,  9,  9,  9,  9,  10,  7,  10}, 
            {11,  11,  9,  9,  9,  9,  9,  9,  9,  10,  10,  10}, 
            {11,  11,  11,  11,  11,  11,  10,  10,  10,  10,  10,  10}, 
            {11,  11,  11,  11,  11,  11,  10,  10,  10,  10,  10,  10}};

    long l = System.currentTimeMillis();
    f(test);
    System.out.println("12x12: " + (System.currentTimeMillis() - l) + "ms");

    for(int[] t : test){
        System.out.println(Arrays.toString(t));
    }

}

ผลิตสิ่งนี้ในเครื่องของฉัน:

12x12: 822ms
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1]
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0]
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
[0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0]

หมายเหตุของ OP: การส่งนี้เกิดขึ้นเมื่อความท้าทายเป็นความท้าทายของรหัสกอล์ฟ ดังนั้นจึงใช้ได้อย่างสมบูรณ์แม้ว่าจะไม่ได้รับการปรับปรุงให้เหมาะสมกับเกณฑ์การชนะในปัจจุบัน!
Stewie Griffin

@StewieGriffin ขอบคุณสำหรับความคิดเห็น เมื่อฉันได้รับโอกาสฉันจะพยายามทำความสะอาดมันเนื่องจากไม่มีรหัสกอล์ฟอีกต่อไปและดูว่าฉันสามารถเพิ่มประสิทธิภาพให้กับความเร็วได้
ไหม

การจับเวลาอย่างเป็นทางการ: 1.2 วินาทีในวันที่ 12x12
isaacg

เรากำลังดองอยู่บางทีคุณอาจช่วยได้ คุณนึกถึงวิธีใดในการสร้างอินสแตนซ์ปริศนาที่ไม่น่าสนใจขนาดใหญ่หรือ
isaacg

4

Clingo , ≈ 7 ms สำหรับ 12 × 12, 116 ไบต์

{t(X,Y):c(X,Y,Z)}=2:-Z=1..n.
:-X=1..n,{t(X,1..n)}!=2.
:-Y=1..n,{t(1..n,Y)}!=2.
:-t(X,Y),t(X+1,Y;X+1,Y+1;X,Y+1;X-1,Y+1).

(ขึ้นบรรทัดใหม่เป็นทางเลือกและไม่ถูกนับ)

ทำงานกับclingo plant.lp - -c n=<n>ที่<n>มีขนาดตาราง รูปแบบการป้อนข้อมูลที่เป็นรายการของc(X,Y,Z).งบสำหรับแต่ละเซลล์ ( X, Y) สีZด้วย 1 ≤ X, Y, Znคั่นด้วยช่องว่างที่เป็นตัวเลือก เอาท์พุทรวมถึงt(X,Y)สำหรับแต่ละต้นไม้ที่ ( X,Y )

เวลาค่อนข้างไร้ความหมายเนื่องจากเป็นเพียงเวลาเริ่มต้นดังนั้นให้พิจารณาการลงคะแนนสำหรับกรณีทดสอบที่มีขนาดใหญ่กว่านี้

การสาธิต

$ clingo plant.lp -c n=12 - <<EOF
> c(1,1,1). c(2,1,1). c(3,1,1). c(4,1,1). c(5,1,1). c(6,1,2). c(7,1,3). c(8,1,3). c(9,1,3). c(10,1,3). c(11,1,4). c(12,1,4).
> c(1,2,1). c(2,2,1). c(3,2,1). c(4,2,1). c(5,2,1). c(6,2,2). c(7,2,3). c(8,2,3). c(9,2,3). c(10,2,3). c(11,2,4). c(12,2,4).
> c(1,3,1). c(2,3,1). c(3,3,1). c(4,3,1). c(5,3,1). c(6,3,2). c(7,3,2). c(8,3,2). c(9,3,2). c(10,3,4). c(11,3,4). c(12,3,4).
> c(1,4,5). c(2,4,5). c(3,4,5). c(4,4,1). c(5,4,6). c(6,4,6). c(7,4,6). c(8,4,7). c(9,4,2). c(10,4,7). c(11,4,8). c(12,4,8).
> c(1,5,5). c(2,5,5). c(3,5,1). c(4,5,1). c(5,5,6). c(6,5,6). c(7,5,6). c(8,5,7). c(9,5,2). c(10,5,7). c(11,5,8). c(12,5,8).
> c(1,6,5). c(2,6,5). c(3,6,6). c(4,6,6). c(5,6,6). c(6,6,6). c(7,6,6). c(8,6,7). c(9,6,7). c(10,6,7). c(11,6,8). c(12,6,8).
> c(1,7,5). c(2,7,5). c(3,7,5). c(4,7,6). c(5,7,9). c(6,7,10). c(7,7,6). c(8,7,6). c(9,7,7). c(10,7,8). c(11,7,8). c(12,7,8).
> c(1,8,9). c(2,8,9). c(3,8,5). c(4,8,9). c(5,8,9). c(6,8,10). c(7,8,10). c(8,8,10). c(9,8,10). c(10,8,11). c(11,8,8). c(12,8,8).
> c(1,9,9). c(2,9,9). c(3,9,9). c(4,9,9). c(5,9,9). c(6,9,10). c(7,9,10). c(8,9,10). c(9,9,10). c(10,9,11). c(11,9,8). c(12,9,11).
> c(1,10,12). c(2,10,12). c(3,10,10). c(4,10,10). c(5,10,10). c(6,10,10). c(7,10,10). c(8,10,10). c(9,10,10). c(10,10,11). c(11,10,11). c(12,10,11).
> c(1,11,12). c(2,11,12). c(3,11,12). c(4,11,12). c(5,11,12). c(6,11,12). c(7,11,11). c(8,11,11). c(9,11,11). c(10,11,11). c(11,11,11). c(12,11,11).
> c(1,12,12). c(2,12,12). c(3,12,12). c(4,12,12). c(5,12,12). c(6,12,12). c(7,12,11). c(8,12,11). c(9,12,11). c(10,12,11). c(11,12,11). c(12,12,11).
> EOF
clingo version 5.1.0
Reading from plant.lp ...
Solving...
Answer: 1
c(1,1,1) c(2,1,1) c(3,1,1) c(4,1,1) c(5,1,1) c(6,1,2) c(7,1,3) c(8,1,3) c(9,1,3) c(10,1,3) c(11,1,4) c(12,1,4) c(1,2,1) c(2,2,1) c(3,2,1) c(4,2,1) c(5,2,1) c(6,2,2) c(7,2,3) c(8,2,3) c(9,2,3) c(10,2,3) c(11,2,4) c(12,2,4) c(1,3,1) c(2,3,1) c(3,3,1) c(4,3,1) c(5,3,1) c(6,3,2) c(7,3,2) c(8,3,2) c(9,3,2) c(10,3,4) c(11,3,4) c(12,3,4) c(1,4,5) c(2,4,5) c(3,4,5) c(4,4,1) c(5,4,6) c(6,4,6) c(7,4,6) c(8,4,7) c(9,4,2) c(10,4,7) c(11,4,8) c(12,4,8) c(1,5,5) c(2,5,5) c(3,5,1) c(4,5,1) c(5,5,6) c(6,5,6) c(7,5,6) c(8,5,7) c(9,5,2) c(10,5,7) c(11,5,8) c(12,5,8) c(1,6,5) c(2,6,5) c(3,6,6) c(4,6,6) c(5,6,6) c(6,6,6) c(7,6,6) c(8,6,7) c(9,6,7) c(10,6,7) c(11,6,8) c(12,6,8) c(1,7,5) c(2,7,5) c(3,7,5) c(4,7,6) c(5,7,9) c(6,7,10) c(7,7,6) c(8,7,6) c(9,7,7) c(10,7,8) c(11,7,8) c(12,7,8) c(1,8,9) c(2,8,9) c(3,8,5) c(4,8,9) c(5,8,9) c(6,8,10) c(7,8,10) c(8,8,10) c(9,8,10) c(10,8,11) c(11,8,8) c(12,8,8) c(1,9,9) c(2,9,9) c(3,9,9) c(4,9,9) c(5,9,9) c(6,9,10) c(7,9,10) c(8,9,10) c(9,9,10) c(10,9,11) c(11,9,8) c(12,9,11) c(1,10,12) c(2,10,12) c(3,10,10) c(4,10,10) c(5,10,10) c(6,10,10) c(7,10,10) c(8,10,10) c(9,10,10) c(10,10,11) c(11,10,11) c(12,10,11) c(1,11,12) c(2,11,12) c(3,11,12) c(4,11,12) c(5,11,12) c(6,11,12) c(7,11,11) c(8,11,11) c(9,11,11) c(10,11,11) c(11,11,11) c(12,11,11) c(1,12,12) c(2,12,12) c(3,12,12) c(4,12,12) c(5,12,12) c(6,12,12) c(7,12,11) c(8,12,11) c(9,12,11) c(10,12,11) c(11,12,11) c(12,12,11) t(1,7) t(1,9) t(2,3) t(2,11) t(3,5) t(3,8) t(4,10) t(4,12) t(5,5) t(5,8) t(6,2) t(6,10) t(7,4) t(7,12) t(8,2) t(8,6) t(9,4) t(9,11) t(10,1) t(10,6) t(11,3) t(11,9) t(12,1) t(12,7)
SATISFIABLE

Models       : 1+
Calls        : 1
Time         : 0.009s (Solving: 0.00s 1st Model: 0.00s Unsat: 0.00s)
CPU Time     : 0.000s

เพื่อให้รูปแบบอินพุต / เอาต์พุตง่ายต่อการจัดการนี่คือโปรแกรม Python สำหรับแปลงจากและเป็นรูปแบบที่กำหนดในการท้าทาย

อินพุต

import sys
print(' '.join("c({},{},{}).".format(x + 1, y + 1, ord(cell) - ord('a') + 1) for y, row in enumerate(sys.stdin.read().splitlines()) for x, cell in enumerate(row)))

เอาท์พุต

import re
import sys
for line in sys.stdin:
    c = {(int(x), int(y)): int(z) for x, y, z in re.findall(r'\bc\((\d+),(\d+),(\d+)\)', line)}
    if c:
        t = {(int(x), int(y)) for x, y in re.findall(r'\bt\((\d+),(\d+)\)', line)}
        n, n = max(c)
        for y in range(1, n + 1):
            print(''.join(chr(ord('aA'[(x, y) in t]) + c[x, y] - 1) for x in range(1, n + 1)))
        print()

ดูเหมือนว่าเรา gonn'a ต้องการกรณีทดสอบที่ใหญ่กว่า Btw คุณจะชนะรุ่นกอล์ฟของคำถามนี้ - แค่ต้องการ 2 วินาทีเปลี่ยนเป็น 1 วินาที
เดฟ

เวลาอย่างเป็นทางการคือ 18 มิลลิวินาทีในวันที่ 12x12 ฉันขอโทษ ตัวอักษร 1 ตัวนั่นเป็นปัญหาของตัวย่อ
isaacg

เรากำลังดองอยู่บางทีคุณอาจช่วยได้ คุณนึกถึงวิธีใดในการสร้างอินสแตนซ์ปริศนาที่ไม่น่าสนใจขนาดใหญ่หรือ
isaacg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.