計(jì)算機(jī)等級(jí)考試C語(yǔ)言程序設(shè)計(jì)例解(02)

字號(hào):

02.找一個(gè)最小的自然數(shù)x,使它等于不同的兩對(duì)自然數(shù)的三次冪之和,即使得:
     x=a*a*a+b*b*b=c*c*c+d*d*d
     其中a,b,c,d都是自然數(shù),且有a!=c和a!=d
    解:
     問(wèn)題要找的解是兩個(gè)自然數(shù)對(duì),以自然數(shù)對(duì)為解的候選者,如程序能這樣枚舉解的候選者,使枚舉出來(lái)的自然數(shù)對(duì)的三次冪之和構(gòu)成一個(gè)不減的序列,則當(dāng)發(fā)現(xiàn)兩個(gè)自然數(shù)對(duì)的三次冪之和相等時(shí),這兩對(duì)自然數(shù)就是問(wèn)題的解。將這種思想寫(xiě)成抽象算法描述如下:
    {
     i1=1;j1=1;x=i1*i1*i1+j1*j1*j1;
     do
     {
     i0=i1;j0=j1;min=x; /*保存上一個(gè)解的候選者*/
     確定下一對(duì)自然數(shù)i1,j1;
     x=i1*i1*i1+j1*j1*j1;
     }while(x!=min);
     printf("%d=%d^3+%d^3=%d^3+%d^3\n",x,i0,j0,i1,j1);
    }
    問(wèn)題已轉(zhuǎn)化成如何按上述要求逐一自然數(shù)對(duì)。
     為了尋找產(chǎn)生候選者規(guī)則的線(xiàn)索,將問(wèn)題簡(jiǎn)化為找一個(gè)最小的自然數(shù)x,使它等于不同的兩對(duì)自然數(shù)的平方之和。下面列出部分兩個(gè)自然數(shù)的平方之和的數(shù)表s[],其中:
     s[i][j]=i*i+j*j
    從上面的s[]表查得:
     50=1*1+7*7=5*5+5*5
     65=1*1+8*8=4*4+7*7
    所以50是兩對(duì)自然 平方和的最小者。要尋找的產(chǎn)生候選者的規(guī)則就是要尋找一個(gè)方法,使枚舉產(chǎn)生的候選者(自然數(shù)對(duì))的平方和構(gòu)成以下數(shù)列:
     2 5 8 10 13 ... 45 50 50
     仔細(xì)考查表中s[i][j]與i和j,不難發(fā)現(xiàn)有以下性質(zhì):
    1) s[i][j]>s[i][k],對(duì)于所有的i,當(dāng)j>k
    2) s[i][j]>s[k][j],對(duì)于所有的j,當(dāng)i>k
    3)s[i][j]=s[j][i]
     因問(wèn)題將自然數(shù)對(duì)(i,j)和(j,i)視為同一個(gè)自然數(shù)對(duì),所以只需考慮i>=j的情況,性質(zhì)1)說(shuō)明對(duì)于表中的每一行,應(yīng)從左到右逐個(gè)考查,且沒(méi)有必要保存一整行的候選者供選擇,一行只要保存一個(gè)已足夠。當(dāng)某行的當(dāng)前候選者已被確認(rèn)不是解時(shí),則可生成該行的下一個(gè)候選者,等候被考慮。
     由以上分析,可用下面的兩個(gè)一維數(shù)組表示當(dāng)前正在考慮的狀態(tài):
     int s[?],j[?];
    其中?意指數(shù)組的大小還未確定。數(shù)組j[]的成份j[k]表示s表中的第k行當(dāng)前待考慮的列號(hào)。所以,s[]和j[]有關(guān)系:
     s[k]=k*k*k+j[k]*j[k]*j[k]
     將以上分析結(jié)果反映到找解方法中,原先的找解算法可改寫(xiě)成如下形式:
    {
     for(k=1;k { /*每行都從第一列一始考查*/
     j[k]=1;
     s[k]=k*k*k+1;
     }
     i=1; /*最初候選者在第一行*/
     do
     {
     min=s[i];i0=i;j0=j[i];
     為i行設(shè)定下一個(gè)候選者存入s[i];
     在s[]中找最小的候選者為正式候選者,并將找到的位置存于i中;
     }while(s[i]!=min);
     printf("%d=%d^3+%d^3=%d^3+%d^3\n",min,i0,j0,i,j[i]);
    }
    按上述算法編寫(xiě)程序還有兩處不足,需進(jìn)一步確定或調(diào)整:一是為個(gè)數(shù)不確定的數(shù)組s[]和j[]送初值;另一個(gè)是個(gè)數(shù)不確定的候選者中選正式候選者。由性持,由性質(zhì)2),引入當(dāng)前考慮的行的范圍,行ih和最小行il,其中ih是指有j[k]為1的最小下標(biāo)k,因?yàn)楫?dāng)前還不可能在ih行之后選到最小的s[i],所以置初值和選最小元可局限于k<=ih的s[k]中進(jìn)行。另外,當(dāng)j[i]=i時(shí),因?qū)表的考查只限于它的左下角,所以對(duì)該行的進(jìn)一步考查應(yīng)放棄。利用這個(gè)事實(shí),程序可引入il表示s表的當(dāng)前行范圍的下界。于是置初值、尋找局限于s表的il 行到 ih行之間。每當(dāng)j[i]=i時(shí),il增1;每當(dāng)j[i]=1時(shí),ih增1,并同時(shí)設(shè)定s[ih]和j[ih]的初值。
     再次把上述思想反映到算法中,找解算法又可改寫(xiě)成如下形式:
    算法--找一個(gè)最小的自然數(shù)x,使它等于不同的兩對(duì)自然 的三次冪之和
    {
     il=1;ih=1; /*首先只局限于第一行*/
     j[1]=1;s[1]=2;i=1;
     d
    {
     min=s[i];i0=i;j0=j[i];
     if(j[i]==1)
     { /*調(diào)整ih,并為j[ih]與s[ih]設(shè)定初值*/
     ih++;
     j[ih]=1;
     s[ih]=ih*ih*ih+1;
     }
     if(j[i]==i)il++; /*調(diào)整il*/
     else
     { /*為i行設(shè)定下一個(gè)待候選者*/
     j[i]++;
     s[i]=i*i*i+j[i]*j[i]*j[i];
     }
     /*以下確定新的i,使得s[i]=min(s[il],...s[ih])*/
     i=il;
     for(k=il+1;k<=ih;k++)
     if(s[k] }while(s[i]!=min(;
     printf("%d=%d^3+%d^3=%d^3+%d^3\n",min,i0,j0,i,j[i]);
    }
    以上算法可作為最后的算法,下面的程序作了必要的優(yōu)化,避免反復(fù)計(jì)算一個(gè)整數(shù)的三次冪。引入數(shù)組p[],其中p[i]存儲(chǔ)i*i*i。