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)
Bunun çift sayılar için en uygun programın 2 katı içinde kalmasını garanti edemem, ancak etkilidir. Tüm geçerli girdiler için 0 <= n < 65536, esasen anlıktır ve en fazla 33 talimatdan oluşan bir program oluşturur. Rastgele bir kayıt boyutu için n(bu sabiti düzelttikten sonra), O(n)en fazla 2n+1talimatla zaman alacaktır .
Bazı İkili Mantık
Herhangi tek sayı n31 adımda ulaşılabilir: do y+=x, alma x,y = 1,1ve daha sonra iki katına tutmak xile x+=x(ilk iki katına yapmak x+=yberi xbaşlamak için garip). x2'nin her gücüne bu şekilde ulaşacaktır (sadece bir sola kaydırma) ve böylece y2'nin ilgili gücünü ekleyerek 1 olacak şekilde herhangi bir biti ayarlayabilirsiniz. 16 bitlik kayıtlar kullandığımız ve birincisi ulaşmak için bir katlama ve bir tane y+=xayarlamak için en fazla 31 ops alırız.
Herhangi bir çift sayı nsadece 2'nin bir gücüdür a, diyelim, tek bir sayı, deyin m; yani n = 2^a * mveya eşdeğer olarak n = m << a. Almak için yukarıdaki işlemi kullanın msonra sıfırlama, xbu 0. yapmak var kadar sol kaydırarak x+=ysetine x = mve daha sonra çift devam x, ilk kez kullanan x+=ykullanarak sonradan ve x+=x.
Ne olursa olsun aTek gereken, olduğu 16-abir vardiya xalmak y=mve ek avardiya sıfırlamak için x=0. Sonra başka bir akayma xgerçekleşecek x=m. Böylece toplam 16+avardiya kullanılır. 16-aAlmak için ayarlanması gereken en fazla bit vardır mve bunların her biri bir tane alacaktır y+=x. Sonunda ne zaman x=0m'ye ayarlayacağımız fazladan bir adıma ihtiyacımız var x+=y. Bu nedenle, herhangi bir çift sayı elde etmek için en fazla 33 adım gerekir.
Elbette, bunu herhangi bir boyut kaydına genelleştirebilirsiniz, bu durumda sırasıyla en fazla zaman alır 2n-1ve 2n+1tek ve çift nbitli tamsayıları seçer.
Optimalliği
Bu algoritma (içinde, yani yakın optimal olan bir program üretir 2n+2ise ntek sayı için adımların en az bir sayı). Belirli bir tek sayı için nise, minci biraz 1 gelen, daha sonra herhangi bir program, en azından alır madımları almak için x=nya da y=n, hızlı sicil değerlerini arttırır olduğu işlem yana x+=xya da y+=y(örneğin, ikiye katlama) ve alır malmak misli mBu algoritma yana 1'den inci bit en alır 2madımları (en fazla iki kat başına iki, geçiş için ve bir y+=xherhangi bir tek sayı yakın en uygun şekilde temsil edilir).
Rakamlar bile o kadar iyi değildir, çünkü xher şeyden önce sıfırlamak için her zaman 16 op kullanır ve örneğin 8'e 5 adımda ulaşılabilir.
İlginçtir, yukarıdaki algoritma asla hiç kullanmaz y+=y, çünkü yher zaman gariptir. Bu durumda, sadece 3 işlemin kısıtlı seti için en kısa programı bulabilir.
Test yapmak
# 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()
Çözümümün gerçekten doğru sonuçlar verdiğini ve tüm geçerli girdiler için hiçbir zaman 33 adımı geçmediğini kontrol etmek için basit bir test yazdım 0 <= n < 65536.
Buna ek olarak, çözümümün çıktısını optimum çıktılarla karşılaştırmak için ampirik bir analiz yapmaya çalıştım - ancak, ilk genişlik aramasının her geçerli giriş için minimum çıktı uzunluğunu elde etmek için çok verimsiz olduğu ortaya çıktı n. Örneğin, çıktıyı bulmak için BFS kullanımı n = 65535makul bir süre içinde sona ermez. Yine de bıraktım bfs()ve önerilere açıkım.
Ancak, kendi çözümümü @ CChak'lara karşı test ettim (burada Python'da uygulandı U). Benimkinin daha kötü olmasını bekliyordum, çünkü daha küçük çiftler için büyük ölçüde verimsiz, ancak tüm aralıkta iki şekilde ortalama, benimki ortalama üretimin ortalama% 10.8 ila% 12.3 daha kısa üretti. Belki de bunun tek sayılarda kendi Vçözümümden daha iyi verimden kaynaklandığını düşündüm, bu yüzden tek sayılarda mayın ve çift sayılarda @ CChak kullanıyor, ancak Varasında (yaklaşık% 10 daha kısa U,% 3 daha uzun S).
x+=xsadece olsaxbile yasaldır ? Ayrıca en kısa program için BFS gibi bir şeyin işe yarayabileceğini düşünüyorum.