Python, 183
def S(n):
b,c,e=16,'x+=x\n','x+=y\n';s=d='y+=x\n';a=i=0
if n<2:return
while~n&1:n>>=1;a+=1
while n:n>>=1;s+=[e,c][i]+d*(n&1);i=1;b-=1
while a:s+=[c,c*b+e*2][i];i=0;a-=1
print(s)
ฉันไม่สามารถรับประกันได้ว่าการเข้าพักจะอยู่ภายใน 2x โปรแกรมที่ดีที่สุดสำหรับตัวเลขที่เท่ากัน แต่มีประสิทธิภาพ สำหรับอินพุตที่ถูกต้องทั้งหมด0 <= n < 65536
เป็นหลักทันทีและสร้างโปรแกรมได้สูงสุด 33 คำสั่ง สำหรับขนาดการลงทะเบียนโดยพลการn
(หลังจากกำหนดค่าคงที่นั้น) จะใช้O(n)
เวลาไม่นาน2n+1
คำแนะนำอย่างมาก
ตรรกะบางอย่าง
จำนวนคี่ใด ๆ ที่n
สามารถเข้าถึงได้ภายใน 31 ขั้นตอน: ทำy+=x
, รับx,y = 1,1
และจากนั้นให้เพิ่มเป็นสองเท่าx
ด้วยx+=x
(สำหรับการเพิ่มเป็นสองเท่าแรกให้ทำx+=y
เนื่องจากx
เป็นเลขคี่ที่จะเริ่มต้นด้วย) x
จะไปถึงพลังทั้งหมดของ 2 ด้วยวิธีนี้ (มันเป็นเพียงกะซ้าย) และคุณสามารถตั้งค่าบิตใด ๆy
ให้เป็น 1 ได้โดยเพิ่มกำลังที่สอดคล้องกันเป็น 2 เนื่องจากเราใช้รีจิสเตอร์ 16 บิตและแต่ละบิตยกเว้น สำหรับครั้งแรกใช้เวลาหนึ่งในการเข้าถึงและเป็นสองเท่าy+=x
ในการตั้งค่าเราได้รับสูงสุด 31 ตัวเลือก
เลขคู่ใด ๆn
เป็นเพียงกำลังบางส่วนของ 2 เรียกว่าa
คูณจำนวนคี่เรียกว่าm
; เช่นหรือเท่ากันn = 2^a * m
n = m << a
ใช้กระบวนการข้างต้นเพื่อรับm
จากนั้นรีเซ็ตx
โดยเลื่อนไปทางซ้ายจนกว่าจะเป็น 0 ทำการx+=y
ตั้งค่าx = m
แล้วทำต่อไปเป็นสองเท่าx
ในครั้งแรกที่ใช้งานx+=y
และใช้งานในภายหลังx+=x
และต่อมาใช้
สิ่งที่a
เป็นก็จะใช้เวลา16-a
กะx
ที่จะได้รับy=m
และเพิ่มเติมการเปลี่ยนแปลงการตั้งค่าใหม่a
จะมีการเปลี่ยนแปลงx=0
อีกครั้งหลังจากนั้น ดังนั้นจึงใช้กะทั้งหมด มีถึงบิตที่จะต้องมีการตั้งค่าที่จะได้รับและแต่ละคนจะใช้เวลาหนึ่ง ในที่สุดเราต้องการขั้นตอนพิเศษเมื่อตั้งค่าเป็น ma
x
x=m
16+a
16-a
m
y+=x
x=0
x+=y
ตั้งค่าให้เมตรดังนั้นจึงต้องใช้เวลาไม่เกิน 33 ขั้นตอนในการรับหมายเลขคู่
แน่นอนว่าคุณสามารถพูดคุยเรื่องนี้กับการลงทะเบียนขนาดใดก็ได้ซึ่งในกรณีนี้จะใช้เวลามากที่สุด2n-1
และเป็น2n+1
ops สำหรับคี่และคู่n
จำนวนเต็มตามลำดับ
optimality
อัลกอริทึมนี้สร้างโปรแกรมที่ใกล้จะเหมาะสมที่สุด (เช่นภายใน2n+2
ถ้าn
เป็นจำนวนขั้นต่ำ) สำหรับจำนวนคี่ สำหรับเลขคี่ที่กำหนดn
ถ้าm
บิต TH เป็นผู้นำ 1 แล้วโปรแกรมใด ๆ ใช้เวลาอย่างน้อยm
ขั้นตอนที่จะได้รับx=n
หรือy=n
เนื่องจากการดำเนินการซึ่งจะเป็นการเพิ่มค่าจิที่เร็วที่สุดคือx+=x
หรือy+=y
(เช่น doublings) และจะใช้เวลาm
doublings ที่จะได้รับm
บิต TH จาก 1. ตั้งแต่ขั้นตอนวิธีการนี้จะใช้เวลาที่มากที่สุด2m
ขั้นตอน (สองที่มากที่สุดต่อการเสแสร้งหนึ่งสำหรับการเปลี่ยนแปลงและเป็นหนึ่งในy+=x
) เลขคี่ใด ๆ ที่เป็นตัวแทนใกล้ได้อย่างดีที่สุด
แม้ตัวเลขจะไม่ค่อยดีนักเนื่องจากมันใช้ 16 ops เพื่อรีเซ็ต x
ก่อนสิ่งอื่นเสมอและ 8 ตัวอย่างเช่นสามารถเข้าถึงได้ภายใน 5 ขั้นตอน
ที่น่าสนใจอัลกอริทึมด้านบนไม่เคยใช้y+=y
เลยเพราะy
มันแปลกเสมอ ในกรณีนี้จริง ๆ แล้วมันอาจค้นหาโปรแกรมที่สั้นที่สุดสำหรับชุดที่ จำกัด ของการดำเนินการเพียง 3
การทดสอบ
# Do an exhaustive breadth-first search to find the shortest program for
# each valid input
def bfs():
d = {(0,1):0}
k = 0xFFFF
s = set(range(k+1))
current = [(0,1)]
nexts = []
def add(pt, dist, n):
if pt in d: return
d[pt] = dist
s.difference_update(pt)
n.append(pt)
i = 0
while len(s) > 0:
i += 1
for p in current:
x,y = p
add((x,x+y&k), i, nexts)
add((y,x+y&k), i, nexts)
if y%2 == 0: add(tuple(sorted((x,y+y&k))), i, nexts)
if x%2 == 0: add(tuple(sorted((x+x&k,y))), i, nexts)
current = nexts
nexts = []
print(len(d),len(s))
# Mine (@rationalis)
def S(n):
b,c,e=16,'x+=x\n','x+=y\n';s=d='y+=x\n';a=i=0
if n<2:return ''
while~n&1:n>>=1;a+=1
while n:n>>=1;s+=[e,c][i]+d*(n&1);i=1;b-=1
while a:s+=[c,c*b+e*2][i];i=0;a-=1
return s
# @CChak's approach
def U(i):
if i<1:return ''
return U(i//2)+'y+=y\n' if i%4==0 else U(i-1)+'y+=x\n'
# Use mine on odd numbers and @CChak's on even numbers
def V(i):
return S(i) if i % 2 == 1 else U(i)
# Simulate a program in the hypothetical machine language
def T(s):
x,y = 1,0
for l in s.split():
if l == 'x+=x':
if x % 2 == 1: return 1,0
x += x
elif l == 'y+=y':
if y % 2 == 1: return 1,0
y += y
elif l == 'x+=y': x += y
elif l == 'y+=x': y += x
x %= 1<<16
y %= 1<<16
return x,y
# Test a solution on all values 0 to 65535 inclusive
# Max op limit only for my own solution
def test(f):
max_ops = 33 if f==S else 1000
for i in range(1<<16):
s = f(i); t = T(s)
if i not in t or len(s)//5 > max_ops:
print(s,i,t)
break
# Compare two solutions
def test2(f,g):
lf = [len(f(i)) for i in range(2,1<<16)]
lg = [len(g(i)) for i in range(2,1<<16)]
l = [lf[i]/lg[i] for i in range(len(lf))]
print(sum(l)/len(l))
print(sum(lf)/sum(lg))
# Test by default if script is executed
def main():
test()
if __name__ == '__main__':
main()
ฉันเขียนการทดสอบอย่างง่าย ๆ เพื่อตรวจสอบว่าโซลูชันของฉันให้ผลลัพธ์ที่ถูกต้องและไม่ผ่านไป 33 ขั้นตอนสำหรับอินพุตที่ถูกต้องทั้งหมด ( 0 <= n < 65536
)
นอกจากนี้ฉันพยายามทำการวิเคราะห์เชิงประจักษ์เพื่อเปรียบเทียบผลลัพธ์ของโซลูชันกับผลลัพธ์ที่ดีที่สุด - อย่างไรก็ตามปรากฎว่าการค้นหาความกว้างแรกนั้นไม่มีประสิทธิภาพเกินกว่าที่จะรับความยาวเอาต์พุตขั้นต่ำสำหรับอินพุตที่ถูกต้องn
ทั้งหมด ตัวอย่างเช่นการใช้ BFS เพื่อค้นหาผลลัพธ์สำหรับn = 65535
จะไม่ยุติในระยะเวลาที่เหมาะสม อย่างไรก็ตามฉันทิ้งไว้bfs()
และเปิดรับข้อเสนอแนะ
อย่างไรก็ตามฉันทดสอบโซลูชันของตัวเองกับ @ CChak (นำไปใช้ใน Python ที่นี่ด้วยU
) ฉันคาดหวังว่าเหมืองของฉันจะแย่ลงเนื่องจากมันไม่มีประสิทธิภาพอย่างมากสำหรับตัวเลขที่เล็กกว่า แต่โดยเฉลี่ยในทั้งสองวิธีทำให้เหมืองของฉันมีความยาวเฉลี่ย 10.8% ถึง 12.3% ฉันคิดว่านี่อาจเป็นเพราะประสิทธิภาพที่ดีขึ้นจากการแก้ปัญหาของฉันเองกับตัวเลขคี่ดังนั้นV
ใช้ทุ่นเลขคี่และ @ CChak เป็นเลขคู่ แต่V
อยู่ในระหว่าง (สั้นกว่าประมาณ 10 U
% นานกว่าประมาณ 3% S
)
x+=x
ต้องตามกฎหมายเท่านั้นทำไมถึงเป็นเช่นx
นั้น? สำหรับโปรแกรมที่สั้นที่สุดฉันคิดว่าบางอย่างเช่น BFS สามารถใช้งานได้