กลยุทธ์การชนะสำหรับเกมก่อสร้างสตริง


14

พื้นหลัง

Alice และ Bob เล่นเกมที่เรียกว่าสร้างคำไบนารี ในการเล่นเกมที่คุณแก้ไขความยาวn >= 0, ชุดGของ length- nคำไบนารีที่เรียกว่าชุดเป้าหมายและ length- nสตริงtที่มีตัวอักษรAและBที่เรียกว่าคำสั่งเปิด เกมเป็นเวลาnผลัดกันและในทางกลับกันiผู้เล่นที่กำหนดโดยเลือกบิตt[i] w[i]เมื่อเกมสิ้นสุดลงผู้เล่นจะดูคำฐานสองที่wพวกเขาสร้าง หากพบคำนี้ในชุดเป้าหมายGอลิซชนะเกม มิฉะนั้นบ๊อบชนะ

ยกตัวอย่างเช่นการแก้ไขให้ของn = 4, และG = [0001,1011,0010] อลิซได้รับการเปิดครั้งแรกและเธอเลือกt = AABA เปิดสองยังเป็นของอลิซและเธอเลือกw[0] = 0 บ๊อบมีการเปิดสามและเขาเลือกw[1] = 0 ในการเลี้ยวโค้งสุดท้ายอลิซเลือกw[2] = 0 w[3] = 1คำที่เป็นผลลัพธ์0001ถูกพบในGดังนั้นอลิซชนะเกม

ตอนนี้ถ้าบ๊อบเลือกw[2] = 1อลิซอาจเลือกw[3] = 0ในรอบสุดท้ายของเธอและยังคงชนะ นั่นหมายความว่าอลิซสามารถชนะเกมได้ไม่ว่าบ็อบจะเล่นอย่างไร ในสถานการณ์เช่นนี้อลิซมีกลยุทธ์ชนะ กลยุทธ์นี้สามารถมองเห็นได้เป็นต้นไม้ไบนารีที่มีป้ายกำกับซึ่งแยกตามระดับที่สอดคล้องกับตาของบ๊อบและทุกสาขามีคำจากG:

A A B A

-0-0-0-1
    \
     1-0

อลิซแสดงตามกิ่งไม้ที่ตาเธอ ไม่ว่าสาขาไหนที่บ๊อบเลือกอลิซก็ชนะในที่สุด

อินพุต

คุณจะได้รับเป็น input ยาวnและชุดGเป็นรายการที่ (อาจจะเป็นที่ว่างเปล่า) nของสตริงที่มีความยาว

เอาท์พุต

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

กฎรายละเอียด

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

กรณีทดสอบ

3 [] -> []
3 [000,001,010,011,100,101,110,111] -> [AAA,AAB,ABA,ABB,BAA,BAB,BBA,BBB]
4 [0001,1011,0010] -> [AAAA,BAAA,AABA]
4 [0001,1011,0010,0110,1111,0000] -> [AAAA,BAAA,ABAA,BBAA,AABA,AAAB]
5 [00011,00110,00111,11110,00001,11101,10101,01010,00010] -> [AAAAA,BAAAA,ABAAA,BBAAA,AABAA,AAABA,BAABA,AAAAB,AABAB]

สนุกกับความเป็นจริง

จำนวนการสั่งซื้อทางกลับกันในการส่งออกคือมักจะเท่ากับจำนวนของคำในชุดประตู


5
ฉันค่อนข้างทึ่งกับความจริงที่ว่าอินพุตและเอาต์พุตมีขนาดเท่ากัน คุณมีหลักฐานหรือการอ้างอิงสำหรับข้อเท็จจริงนี้หรือไม่? ฉันสงสัยว่ามีวิธีการคำนวณฟังก์ชั่นนี้ที่รักษาขนาดโดยสังเขปหรือไม่
xnor

2
กรณีทดสอบของคุณ # 5 ขัดแย้งกับข้อเท็จจริงที่สนุกสนานของคุณ ...
mbomb007

3
@ mbomb007 กรณีทดสอบ # 5 รายการ11101สองครั้ง ความจริงก็ยังคงสนุกสำหรับชุด Zgarb อาจข้อมูลประกอบด้วยองค์ประกอบที่ซ้ำกันหรือเป็นข้อผิดพลาดหรือไม่?
xnor

@xnor นี่คือสิ่งที่เกิดขึ้นในการวิจัยของฉันในขณะที่ผ่านมา ฉันมีหลักฐานในเอกสารฉบับนี้หน้า 16 แต่โดยพื้นฐานแล้วมันเหมือนกับของคุณ
Zgarb

1
@ xnor อย่างสังหรณ์ใจไม่ว่าในกรณีใด ๆ ถ้าทั้ง 0 และ 1 เป็นตัวเลือกที่ชนะแล้วอลิซหรือบ๊อบก็สามารถเลือกท่าต่อไปได้ หากมีตัวเลือกชนะเพียงตัวเดียวอลิซจะต้องเลือกตัวเลือกถัดไป ดังนั้นจำนวนตัวเลือกสำหรับสตริงจึงเท่ากับจำนวนตัวเลือกของกลยุทธ์การชนะ แทบจะไม่เข้มงวด แต่น่าสนใจ
เล่นแร่แปรธาตุ

คำตอบ:


1

Dyalog APL, 59 ไบต์

{(a≡,⊂⍬)∨0=⍴a←∪⍵:a⋄(∇h/t)(('A',¨∪),'B',¨∩)∇(~h←⊃¨a)/t←1↓¨a}

อัลกอริทึมเช่นเดียวกับในโซลูชันของ @ xnor

(a≡,⊂⍬)∨0=⍴a←∪⍵:a
           a←∪⍵    ⍝ "a" is the unique items of the argument
        0=⍴a       ⍝ is it empty?
 a≡,⊂⍬             ⍝ is it a vector that contains the empty vector?
       ∨       :a  ⍝ if any of the above, return "a"

(∇h/t)(('A',¨∪),'B',¨∩)∇(~h←⊃¨a)/t←1↓¨a
                                 t←1↓¨a  ⍝ drop an item from each of "a" and call that "t"
                         ~h←⊃¨a          ⍝ first of each of "a", call that "h", then negate it
                                /        ⍝ use "~h" as a boolean mask to select from "t"
                       ∇                 ⍝ apply a recursive call
(∇h/t)                                   ⍝ use "h" as a boolean mask on "t", then a recursive call
      (('A',¨∪),'B',¨∩)                  ⍝ apply a fork on the results from the two recursive calls:
       ('A',¨∪)                          ⍝   prepend 'A' to each of the intersection
               ,                         ⍝   concatenated with
                'B',¨∪                   ⍝   prepend 'B' to each of the union

13

Python, 132

def f(S,n):
 if n<1:return S
 a,b=[f({x[1:]for x in S if x[0]==c},n-1)for c in'01']
 return{'A'+y for y in a|b}|{'B'+y for y in a&b}

ตัวอย่างการเรียกใช้:

f({'000','001','010','011','100','101','110','111'},3) == 
{'ABA', 'ABB', 'AAA', 'AAB', 'BBB', 'BBA', 'BAB', 'BAA'}

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

นี่คือวิธีการเรียกซ้ำได้ทางคณิตศาสตร์ น่าเสียดายที่ PPCG ยังขาดการแสดงผลทางคณิตศาสตร์ดังนั้นฉันจะต้องใช้บล็อคโค้ด

วัตถุที่น่าสนใจคือชุดของสตริง ให้|เป็นตัวแทนของชุดสหภาพและ&เป็นตัวแทนของชุดจุดตัด

หากcเป็นตัวอักษรให้c#Sเป็นตัวแทนของการเพิ่มตัวละครcSสตริงทั้งหมดใน ตรงกันข้ามให้หดตัวc\Sเป็นสายหนึ่งในตัวละครสั้นSติดตามตัวละครเริ่มต้นที่เช่นc0\{001,010,110,111} = {01,10}

เราสามารถแบ่งชุดของสตริงได้อย่างมีเอกลักษณ์ Sมีตัวอักษรในอักขระ01ของพวกเขาเป็น

S = 0#(0\S) | 1#(1\S)

จากนั้นเราสามารถแสดงฟังก์ชั่นที่ต้องการfดังนี้ด้วยเคสฐานในสองบรรทัดแรกและสามารถเรียกซ้ำได้ในบรรทัดสุดท้าย:

f({})   = {}
f({''}) = {''}
f(S)    = A#(f(0\S)|f(1\S)) | B#(f(0\S)&f(1\S))

nโปรดทราบว่าเราไม่จำเป็นต้องใช้ความยาว

ทำไมจึงใช้งานได้ Sลองคิดเกี่ยวกับการย้ายสายที่ช่วยให้อลิซชนะสำหรับชุดของสตริง

ถ้าตัวอักษรตัวแรกคือAอลิซสามารถเลือกย้ายครั้งแรก ( '0' หรือ '1') ให้เธอเลือกที่จะลดปัญหาไปหรือS0 S1ดังนั้นตอนนี้สตริงการย้ายที่เหลือจะต้องมีอย่างน้อยหนึ่งf(S0)หรือf(S1)|เพราะฉะนั้นเราใช้เวลาสหภาพของพวกเขา

ในทำนองเดียวกันถ้าตัวอักษรตัวแรกคือ 'B' Bob จะเลือกและเขาจะเลือกตัวที่แย่กว่าสำหรับ Alice ดังนั้นสตริงการเคลื่อนไหวที่เหลือจะต้องอยู่ในจุดตัด (& )

กรณีฐานเพียงตรวจสอบว่าSว่างเปล่าหรือไม่ในตอนท้าย หากเราติดตามความยาวของสตริงnโดยการลบ 1 ทุกครั้งที่เราเรียกเก็บเงินใหม่ฐานสามารถเขียนแทนได้:

f(S) = S if n==0

วิธีการแก้ปัญหา recursive ยังได้อธิบายถึงความเป็นจริงที่สนุกที่มีขนาดเดียวกับf(S) Sมันเป็นเรื่องจริงสำหรับคดีพื้นฐานและคดีอุปนัย

f(S) = A#(f(0\S)|f(1\S)) | B#(f(0\S)&f(1\S))

เรามี

size(f(S)) = size(A#(f(0\S)|f(1\S)) | B#(f(0\S)&f(1\S)))
           = size(A#(f(0\S)|f(1\S))) + size(B#(f(0\S)&f(1\S))))
           = size((f(0\S)|f(1\S))) + size((f(0\S)&f(1\S))))
           = size(f(0\S)) + size(f(1\S))  [since size(X|Y) + size(X&Y) = size(X) + size(Y)]
           = size(0\S) + size(1\S)
           = size(S)

TypeError: 'int' object is not subscriptableใช้รหัสของคุณให้ คุณมีลิงค์ไปยังโปรแกรมที่รันได้หรือไม่? ฉันเพิ่งวางมันและวิ่งไปกับมันprint f([0001,1011,0010],4)
mbomb007

@ mbomb007 f({'000','001','010','011','100','101','110','111'},3)ความต้องการฟังก์ชั่นที่จะเรียกเช่น คุณได้รับข้อผิดพลาดด้วยวิธีนี้หรือไม่?
xnor

อาฉันไม่เห็นว่าฉันไม่มีคำพูดขอบคุณ นอกจากนี้ยังทำงานด้วยprint f(['0001','1011','0010'],4)
mbomb007

หากคุณต้องการรันโปรแกรมnโดยไม่ขึ้นอยู่กับพารามิเตอร์มันจะเป็นเช่นนั้นn=len(S[0])if S!=[]else 0
mbomb007

เรียกใช้ที่นี่: repl.it/7yI
mbomb007
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.