趣題:量子計算機、另類程式語言和冪函式的解釋

matrix67發表於2008-03-21

    很久沒有更新和資訊學有關的東西了。今天和大家分享一個非常有趣的題目,我已經很久沒看見如此精彩有趣的題目了。為了引入這個問題,我們先來介紹一個假想的程式語言QCPL。就像LISP一樣,它是一個基於函式的語言:沒有變數,沒有for迴圈,一切東西都是用函式來表示的。另外,就像FORTRAN一樣,QCPL語言不支援遞迴,也就是說一個函式不能遞迴地呼叫自己。QCPL的另一個有趣的特點是,所有的函式都只能返回一個Boolean值。比如說,下面這個函式的作用就是判斷x+2和y+2的乘積是否等於z:
MULT_PLUS_TWO(x,y,z): (x+2)*(y+2)=z

    QCPL也有邏輯運算子。事實上,QCPL裡的合法運算子一共只有8個,其中6個分別如下:

運算子 |  作用  |     輸入      |     輸出
-------+--------+---------------+---------------
  +    |  相加  |  兩個自然數   |  一個自然數
  *    |  相乘  |  兩個自然數   |  一個自然數
  =    |  等於  |  兩個自然數   | 一個Boolean值
  &    | 邏輯和 | 兩個Boolean值 | 一個Boolean值
  |    | 邏輯或 | 兩個Boolean值 | 一個Boolean值
  !    | 邏輯非 | 一個Boolean值 | 一個Boolean值


    另外兩個運算子就要重點介紹了。這是QCPL語言真正牛B的地方——它是專門為量子計算機設計的!你可以讓這臺計算機平行地窮盡完某些變數所有可能的取值,這一切僅僅在一瞬間內就可以完成。這兩個特殊的運算子(以後我們管它們叫做“定量運算子”)就是專門用來幹這件牛B事的:"Ex"是“存在性定量運算子”,表示讓計算機找出是否存在一個滿足表示式的自然數x;"Ax"是“通用性定量運算子”,用於詢問計算機該表示式是否對所有的自然數x均成立。比如,運用定量運算子,我們可以立即寫出素數/合數判斷函式:
COMPOSITE(n): Ex,Ey,MULT_PLUS_TWO(x,y,n)
PRIME(n): !(COMPOSITE(n)|n=0|n=1)

    其中,Ex,Ey,MULT_PLUS_TWO(x,y,n)的意思就是說,是否存在某一對x和y,使得MULT_PLUS_TWO(x,y,n)為真。只要(某一個平行世界裡的)計算機找到了任何一對滿足條件的x和y,整個COMPOSITE(n)立即返回True。如果對於所有的自然數x和y,MULT_PLUS_TWO(x,y,n)都不可能為真時,整個函式才返回False。別忘了這是一臺量子計算機,窮舉的過程可以在一瞬間內完成。

    好了,下面我們再給出幾個基本的函式。函式SUM用於計算x加y是否等於z,而函式PRODUCT則用於檢驗x乘以y是否等於z:
SUM(x,y,z): x+y=z
PRODUCT(x,y,z): x*y=z

    現在,你的任務就是寫出一個函式POWER(x,y,z),當且僅當x的y次方等於z時函式才返回True。相信我,這道題沒有那麼容易。


==================華麗的分割線==================

    這真的是一道難題。你必須要跳出常規的程式設計思路,找出與這種全新的程式語言相符的“演算法”。這裡是沒有迴圈結構的,但它有一個更牛B的東西,它可以在一瞬間窮舉所有可能的變數。也就是說,交給這臺計算機的問題最好都是“是否存在一個什麼什麼,使得某某東西成立”的形式。把我們的題目“翻譯”過去,就是:是否存在一個數列{A_n},滿足A_0=1,且對i>0都有A_i=A_(i-1)*x,並且數列中的A_y項恰好等於z?注意到QCPL裡面只有加法和乘法,因此我們不得不借用數列的概念來描述x的冪。可惜的是QCPL語言又不支援數列結構,因此我們不得不把整個數列“編碼”成一個數。最簡單的編碼方式就是使用n進位制儲存數列中的所有數,其中n要比所有的A_i都要大。現在問題又來了,我們如何從這個已經編碼的數列中“提取”指定位置上的數?想了半天想不出辦法,我們突然想到,為什麼不把數列本身的序號也帶進這個數列中?這樣我們可以用一個存在性定量運算子來確定我們需要的數所在的位置。這樣,我們可以把有序數對(x^i,i)作為數列的元素,則問題轉換為檢查數列中是否存在(z,y)一項。而每個有序數對(a,b)也同樣可以用類似地方法進行編碼:選取一個大於所有b的數m,則數對(a,b)和數a*m+b一一對應。

    好了,讓我們重新整理一下我們的思路。我們需要讓計算機尋找一個數列,數列的元素是一個個有序數對,其中第一個元素是(1,0),最後一個元素是(z,y),並且(A_i, B_i)總是等於(A_(i-1) * x, B_(i-1) + 1)。為了把數列轉換為QCPL可以接受的形式,我們選取一個大於y的數m,把數對(a,b)轉化為a*m+b;再選取一個不小於(z+1)*(y+1)的數n,把數列轉化為一個n進位制的數。這樣最終編碼出的結果應該是Σn^i*(A_i*m+B_i)。
    (a,b)與a*m+b之間的轉換需要用到函式DIVMOD,它用於計算n除以m的商和餘數是否為a,b,定義為:
DIVMOD(n,m,a,b): LT(b,m)&(n=m*a+b)
    其中,LT(b,m)返回True當且僅當b<m。這些比較函式可以用下面的方式定義出來。
LE(a,b): Ex, a+x=b  /* a<=b */
GE(a,b): LE(b,a)    /* a>=b */
LT(a,b): !GE(a,b)   /* a<b */
GT(a,b): !LE(a,b)   /* a>b */
NE(a,b): !(a=b)     /* a≠b */


    下面這個函式用於提取一個n進位制數的某一位上的數字,其中引數a表示整個數列編碼後的數,n表示編碼所用的基數,引數v的值應為n^i,函式返回數列中的第i個數是否為x。這個x應該等於a除以v的商,再除以n的餘數。這個函式定義為:
ELEMENT(a,n,v,x): Er,Ey,Eq,DIVMOD(a,v,r,y)&DIVMOD(r,n,q,x)
    為了更好的理解這個函式,考慮一個十進位制數12345,顯然有:
12345 ÷ 100 = 123 … 45
123 ÷ 10 = 12 … 3
    最後的餘數3就是我們想要提取出來的數。上面的例子中,100就是那個v,123和45分別是r和y,12和3分別是q和x。

    但要想判斷v的值是否等於n^i,問題似乎又回到了起始點。不過,不同的是,現在再來判斷v=n^i要簡單多了,因為我們不需要指定指數i的值(數的位置可以從數列本身中獲知),並且我們可以任意取一個自己覺得用著方便的底數n。事實上,當n為一個質數p時,判斷x是否為p的冪非常簡單:
PRIMEPOWER(p,x): (x=1)|Aa,Ab,(!(a*b=x))|(!PRIME(a))|(p=a)
    這個函式的基本思路就是,如果p是一個質數,而x是p的冪,那麼p是x的唯一一個質因子。也就是說,對於任何一個自然數a,要麼它等於p,要麼它不是一個質數,否則的話a*b就不可能等於x。函式用到了我們題目中引入的PRIME函式。

    一切準備就緒了。下面我們需要分別寫出數列的三個約束條件。首先,我們需要保證數列以(1,0)開頭,即編碼之後的p進位制數a的最低位上的數字為m,也即a除以p的餘數為m。於是,第一個條件可以寫作:
CONDITION_ONE(a,p,m): Er,DIVMOD(a,p,r,m)
    接下來,我們希望數列以(z,y)結尾,即a的最高位是m*z+y。換句話說,a除以某個p的冪後,得到的商正好等於m*z+y。於是,我們把條件二寫成:
CONDITION_TWO(a,p,m,z,y): Ev,Er,En,PRIMEPOWER(p,v) & DIVMOD(a,v,n,r) & DIVMOD(n,m,z,y)
    最後,我們需要保證這個數列中(除最後一項外)的每一項都與它的下一個數對有“乘以x”和“加1”的遞推關係。這個條件可以寫成:
CONDITION_THREE(a,p,m,x):
Av,(!PRIMEPOWER(p,v)) |  GT(v*p,a) |    /* ignoring the last element of a */
(Ed,Ee,Eq,Er,Es,Et, ELEMENT(a,p,v,d) & ELEMENT(a,p,v*p,e) & DIVMOD(d,m,q,r) & DIVMOD(e,m,s,t) & (q*x=s) & (r+1=t))


    最後,我們只需要把這三個約束條件結合起來,詢問計算機是否存在同時滿足這三個條件的序列a。我們最終的POWER函式為:
POWER(x,y,z):
(!((x=0)&(y=0))) & /* avoiding 0^0 */
Ea, /* a is our "proof" sequence */
Ep, /* p is the prime used in decoding a */
Em, /* m is used in decoding tuples within a */
GT(m,y) & PRIME(p) & GT(p,m*(z+1)) & CONDITION_ONE(a,p,m) & CONDITION_TWO(a,p,m,z,y) & CONDITION_THREE(a,p,m,x)


參考資料:http://www.brand.site.co.il/riddles/200801q.html

相關文章