การยกเว้นแมนฮัตตันกรณีที่เลวร้ายที่สุด


20

ลองนึกภาพตารางWโดยHของสี่เหลี่ยมที่ล้อมรอบด้วยวงแหวน รายการจะถูกวางลงบนตารางดังนี้

รายการแรกที่สามารถวางบนตารางใด ๆ แต่รายการที่ตามมาจะต้องไม่เป็นภายในระยะแมนฮัตตัน Rของรายการใด ๆ ก่อนหน้า (ยังเป็นที่รู้จักกันเป็นย่าน Von Neumann ของช่วงR ) การเลือกตำแหน่งอย่างระมัดระวังช่วยให้การติดตั้งรายการจำนวนมากเข้ากับกริดก่อนที่จะไม่มีตำแหน่งที่ถูกต้องอีกต่อไป อย่างไรก็ตามให้พิจารณาถึงเป้าหมายตรงกันข้าม: จำนวนไอเท็มที่ต่ำที่สุดที่สามารถวางและไม่อยู่ในตำแหน่งที่ถูกต้องคืออะไร?

นี่คือโซนการยกเว้นรัศมี 5:

เขตการยกเว้นรัศมี 5

นี่คือโซนยกเว้นรัศมี 5 อีกครั้งคราวนี้อยู่ใกล้กับขอบเพื่อให้เห็นพฤติกรรมการห่อที่ชัดเจน:

การตัดรัศมี 5 โซนยกเว้น

อินพุต

สามจำนวนเต็ม:

  • W : ความกว้างของกริด (จำนวนเต็มบวก)
  • H : ความสูงของกริด (จำนวนเต็มบวก)
  • R : รัศมีของเขตการยกเว้น (จำนวนเต็มไม่เป็นลบ)

เอาท์พุต

จำนวนเต็มNซึ่งเป็นจำนวนไอเท็มที่เล็กที่สุดที่สามารถวางเพื่อป้องกันตำแหน่งที่ถูกต้องเพิ่มเติม

รายละเอียด

  • รัศมีศูนย์ให้เขตการยกเว้น 1 สี่เหลี่ยมจัตุรัส (หนึ่งรายการที่ถูกวางบน)
  • รัศมีของ N ไม่รวมถึงโซนที่สามารถเข้าถึงได้ในขั้นตอน N orthogonal (จำได้ว่าขอบห่อ toroidally)

รหัสของคุณจะต้องใช้กับตัวพิมพ์เล็ก ๆ น้อย ๆ ของR = 0 แต่ไม่จำเป็นต้องทำงานกับW = 0 หรือH = 0

รหัสของคุณยังต้องรับมือกับกรณีที่R > WหรือR > H

กำหนดเวลาและกรณีทดสอบ

รหัสของคุณจะต้องสามารถจัดการกับกรณีทดสอบทั้งหมดและแต่ละกรณีทดสอบจะต้องเสร็จสิ้นภายใน 5 นาที สิ่งนี้ควรง่าย (ตัวอย่างโซลูชัน JavaScript ใช้เวลาสองสามวินาทีในแต่ละกรณีทดสอบ) การ จำกัด เวลาส่วนใหญ่จะยกเว้นวิธีการใช้กำลังดุร้ายที่สุด วิธีการตัวอย่างยังคงเป็นกำลังดุร้าย

หากรหัสของคุณเสร็จสมบูรณ์ภายใน 5 นาทีในเครื่องหนึ่ง แต่ไม่ใช่ในรหัสอื่นที่จะปิดพอ

กรณีทดสอบในรูปแบบอินพุต: ส่งออกเป็นW H R : N

5 4 4 : 1
5 4 3 : 2
5 4 2 : 2
5 4 1 : 5

7 5 5 : 1
7 5 4 : 2
7 5 3 : 2
7 5 2 : 4

8 8 8 : 1
8 8 7 : 2
8 8 6 : 2
8 8 5 : 2
8 8 4 : 2
8 8 3 : 4

 7  6  4 : 2
 7  6  2 : 4
11  7  4 : 3
11  9  4 : 4
13 13  6 : 3
11 11  5 : 3
15 14  7 : 2
16 16  8 : 2

ตัวอย่างเพื่อช่วยให้เห็นภาพและเล่นกับแนวคิด

ตัวอย่างการแก้ปัญหา (ungolfed)

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


4
ตัวอย่างโค้ดที่ยอดเยี่ยม!
ยืด Maniac

@StretchManiac ขอบคุณ :) ฉันพยายามที่จะเรียนรู้ JavaScript ดังนั้นข้อเสนอแนะใด ๆ ยินดีต้อนรับ
trichoplax

1
นั่นเป็นตัวอย่างที่ดีทีเดียว ฉันชอบโทนสีที่เหมือนกัน มันมาจากจานสีหรือไม่?
ไมล์

@miles ขอบคุณ - สีเป็นสิ่งที่เดาได้และปรับจูนเล็กน้อย (แต่ไม่มาก - มันยังคงเป็นรหัสสีตัวอักษรทั้ง 3 ตัวแทนที่จะเป็น 6) คุณสามารถดูสีที่ใช้ในบล็อกที่สามของบรรทัดในโค้ดตัวอย่าง
trichoplax

คำตอบ:


5

Python 2, 216 182 ไบต์

def f(W,H,R):L={(i%W,i/W)for i in range(W*H)};M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R};g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1]);return g(M)

f(16,16,8)การป้อนข้อมูลเช่น ใช้อัลกอริทึมเดียวกันกับตัวอย่างของ @ trichoplaxแต่มีหลายเซต ตอนแรกฉันไม่ได้วางไอเท็มแรก(0, 0)แต่ก็ทำให้มันสำลักในบางกรณี

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

(ขอบคุณ @trichoplax สำหรับความช่วยเหลือในการเล่นกอล์ฟ)

ขยาย:

def f(W,H,R):
  # All cells
  L={(i%W,i/W)for i in range(W*H)}                 

  # Mask: Complement of exclusion zone around (0, 0) 
  M={(x,y)for x,y in L if min(x,W-x)+min(y,H-y)>R}

  # Place recursively
  g=lambda s:min([1+g(s-{((a+x)%W,(b+y)%H)for x,y in L-M})for a,b in s]or[1])
  return g(M)

2

Python 3, 270 262 260 251 246 226

(ขอบคุณ Sp3000 สำหรับ:

  • -~ แทน +1 , ซึ่งจะช่วยให้ฉันลดพื้นที่หลังจาก return ในบรรทัดสุดท้าย
  • W*Hการสูญเสียวงเล็บฟุ่มเฟือยรอบ
  • lambdas ...
  • วางทุกอย่างไว้ในบรรทัดเดียว
  • python modulo %ให้ผลเป็นบวกสำหรับจำนวนลบเพื่อบันทึกอีก 20 ไบต์)

นี่คือคำตอบตัวอย่าง JavaScript จากคำถามที่ย้ายไปยัง Python 3

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

คำอธิบาย

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

รหัส Golfed:

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

รหัสไม่ได้รับการตอบกลับ:

def calculate(W, H, R):
    starting_min = W * H + 1
    cells = [0] * (W * H)
    grid_state = grid_with_item_added(cells, 0, 0, W, H, R)
    return min_from_here(grid_state, starting_min, W, H, R) + 1

def min_from_here(grid_state, starting_min, W, H, R):
    no_cells = True
    min = starting_min
    for x in range(W):
        for y in range(H):
            if grid_state[x + W * y] == 0:
                no_cells = False
                new_grid_state = grid_with_item_added(grid_state, x, y, W, H, R)
                m = min_from_here(new_grid_state, starting_min, W, H, R)
                if m < min:
                    min = m

    if no_cells:
        return 0
    else:
        return min + 1

def grid_with_item_added(grid_state, x, y, W, H, R):
    grid = grid_state[:]
    for a in range(W):
        for b in range(H):
            if manhattan_distance(a, b, x, y, W, H) <= R:
                grid[a + W * b] = 1

    return grid

def manhattan_distance(a, b, c, d, W, H):
    horizontal = min(abs(W + c - a) % W, abs(W + a - c) % W)
    vertical = min(abs(H + d - b) % H, abs(H + b - d) % H)
    return horizontal + vertical


if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(calculate(int(arguments[0]), int(arguments[1]), int(arguments[2])))

รหัส ungolfed กำหนดฟังก์ชั่นและรวมถึงรหัสเพื่อให้มันถูกเรียกจากบรรทัดคำสั่ง รหัสแข็งแรงเล่นกอล์ฟเพียงกำหนดฟังก์ชั่นซึ่งเป็นที่เพียงพอสำหรับคำถามกอล์ฟรหัสมาตรฐาน

หากคุณต้องการทดสอบรหัส golfed จากบรรทัดคำสั่งนี่คือการจัดการบรรทัดคำสั่งรวมอยู่ด้วย (แต่ไม่ใช่ golfed):

บรรทัดคำสั่งรหัส golfed ที่ทดสอบได้

def C(W,H,R):r=range;M=lambda g:min([M(G(g,x,y))for x in r(W)for y in r(H)if g[x+W*y]]or[-1])+1;G=lambda g,x,y:[g[a+W*b]if min((x-a)%W,(a-x)%W)+min((y-b)%H,(b-y)%H)>R else 0for b in r(H)for a in r(W)];return-~M(G([1]*W*H,0,0))

if __name__ == '__main__':
    import sys
    arguments = sys.argv[1:]
    if len(arguments) < 3:
        print('3 arguments required: width, height and radius')
    else:
        print(C(int(arguments[0]), int(arguments[1]), int(arguments[2])))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.