亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標(biāo)題: 變態(tài)的算法題 [打印本頁]

作者: DNFCF    時(shí)間: 2011-04-27 21:00
標(biāo)題: 變態(tài)的算法題
一個(gè)N位的十進(jìn)制正整數(shù),如果它的每個(gè)位上的數(shù)字的N次方的和等于這個(gè)數(shù)本身,則稱其為花朵數(shù)。
例如:
當(dāng)N=3時(shí),153就滿足條件,因?yàn)?1^3 + 5^3 + 3^3 = 153,這樣的數(shù)字也被稱為水仙花數(shù)(其中,“^”表示乘方,5^3表示5的3次方,也就是立方)。
當(dāng)N=4時(shí),1634滿足條件,因?yàn)?1^4 + 6^4 + 3^4 + 4^4 = 1634。
當(dāng)N=5時(shí),92727滿足條件。
實(shí)際上,對N的每個(gè)取值,可能有多個(gè)數(shù)字滿足條件。

程序的任務(wù)是:求N=21時(shí),所有滿足條件的花朵數(shù)。注意:這個(gè)整數(shù)有21位,它的各個(gè)位數(shù)字的21次方之和正好等于這個(gè)數(shù)本身。
如果滿足條件的數(shù)字不只有一個(gè),請從小到大輸出所有符合條件的數(shù)字,每個(gè)數(shù)字占一行。因?yàn)檫@個(gè)數(shù)字很大,請注意解法時(shí)間上的可行性。要求程序在3分鐘內(nèi)運(yùn)行完畢。
作者: molin0010    時(shí)間: 2011-04-27 22:21
# include <stdio.h>
# include <math.h>

int IsYes(int goal, int len)
{
        int i = 0, sum = 0, goal1=goal;
        int * pArr;

        pArr = (int)malloc(sizeof(int) * len);
        while(goal > 10)
        {
                pArr[i] = goal % 10;
                i++;
                goal /= 10;
        }
        pArr[i] = goal;

        for(i=0; i<len; i++)
        {
                sum += pow(pArr[i], len);
        }
        if(sum == goal1)return 1;
        else return 0;
}

int main(void)
{
        int len = 3, i = 0;
        int LBound = 0, UBound = 0;

        scanf("%d", &len);
        LBound = pow(10, len-1);
        UBound = pow(10, len);

        for(i=LBound; i<UBound; i++)
        {
                if( IsYes(i, len) )printf("%d\n", i);
        }

        return 0;
}
作者: molin0010    時(shí)間: 2011-04-27 22:28
我錯(cuò)了  沒看到后面的 程序的任務(wù)是:求N=21時(shí)
作者: damcool    時(shí)間: 2011-04-28 08:27
大數(shù)乘法和加法問題
作者: hellioncu    時(shí)間: 2011-04-28 08:44
這個(gè)肯定不能死算吧
作者: cokeboL    時(shí)間: 2011-04-28 09:25
感覺主要是時(shí)間問題吧
作者: noword2k    時(shí)間: 2011-04-28 10:11
要先完成一個(gè)大數(shù)運(yùn)算庫。
作者: cjaizss    時(shí)間: 2011-04-28 14:40
我的想法是湊數(shù),8^21已經(jīng)很小,
7^21已經(jīng)很小,對于9^21大小都可以忽略.
9肯定是主流
但不能超過9個(gè)
于是可以從開始湊
1,2,3,4,5,6,7,8,9個(gè)9開始湊
作者: julu99    時(shí)間: 2011-04-28 14:49
可以把N=3那肯定是0-3之間,得到的結(jié)果,在是N=5之間,在是N=7之間,這個(gè)題可以用數(shù)學(xué)的的思維去想。
作者: A.com    時(shí)間: 2011-04-28 17:40
本帖最后由 A.com 于 2011-04-28 17:52 編輯

其實(shí)就是0、1、2097152……9^21的組合,要求組合的和是個(gè)21位的數(shù)字且順序符合。
先湊夠數(shù)字,就是21個(gè)數(shù)之和大于10^20。然后是檢測21個(gè)元素的集合和這個(gè)和的數(shù)字集合是否一致
程序需要循環(huán)21^21次。。。
作者: pmerofc    時(shí)間: 2011-04-28 22:03
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽
作者: DNFCF    時(shí)間: 2011-04-28 22:04
回復(fù) 8# cjaizss


    不懂。。。。
作者: DNFCF    時(shí)間: 2011-04-28 22:05
回復(fù)  DNFCF


      硬件環(huán)境是什么
pmerofc 發(fā)表于 2011-04-28 22:03



    硬件可以不考慮,這個(gè)主要是考算法。。。。
作者: pmerofc    時(shí)間: 2011-04-28 22:07
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽
作者: DNFCF    時(shí)間: 2011-04-28 22:09
回復(fù)  DNFCF


    問題是要求3分鐘,有的機(jī)器快,有的機(jī)器慢
pmerofc 發(fā)表于 2011-04-28 22:07



    老大,你先忽略這個(gè)時(shí)間限制行不??先給個(gè)算法思路吧。。。。
作者: pmerofc    時(shí)間: 2011-04-28 22:13
提示: 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽
作者: DNFCF    時(shí)間: 2011-04-28 22:28
我的想法和10樓差不多

先把 0~9 的21次方算好存起來
然后從 10的20次方開始 到 10的21次方-1 窮舉 計(jì)算 ...
pmerofc 發(fā)表于 2011-04-28 22:13



    問題是數(shù)太大了,會(huì)溢出的???
作者: cjaizss    時(shí)間: 2011-04-28 22:37
問題是數(shù)太大了,會(huì)溢出的???
DNFCF 發(fā)表于 2011-04-28 22:28


不是窮舉,是湊數(shù)。
看看每個(gè)數(shù)的差距
linux-0gt0:~ # bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
for(i=1;i<=9;i++)
print i^21,"\n"
1
2097152
10460353203
4398046511104
476837158203125
21936950640377856
558545864083284007
9223372036854775808
109418989131512359209
作者: DNFCF    時(shí)間: 2011-04-28 22:57
不是窮舉,是湊數(shù)。
看看每個(gè)數(shù)的差距
linux-0gt0:~ # bc
bc 1.06
Copyright 1991-1994, 1997, 199 ...
cjaizss 發(fā)表于 2011-04-28 22:37



    可是在C語言下,好像超過10位就會(huì)溢出啊,怎么解決。?
作者: KBTiller    時(shí)間: 2011-04-29 06:30
本帖最后由 KBTiller 于 2011-04-29 06:40 編輯
可是在C語言下,好像超過10位就會(huì)溢出啊,怎么解決??
DNFCF 發(fā)表于 2011-04-28 22:57



    想辦法創(chuàng)造新的“類型”。編程的樂趣之一就是這種創(chuàng)造性。感覺你還沒體會(huì)到什么是數(shù)據(jù)結(jié)構(gòu)
    手懶,抄段書(自《狂人C》第3章)給你,希望能對你有所啟發(fā)


1976年,著名的計(jì)算機(jī)大師、Pascal語言之父Niklaus Wirth提出

       算法 + 數(shù)據(jù)結(jié)構(gòu) = 程序



Algorithms + Data Structures = Programs
    ……
   例題:編程求123456×654321。
   ……
   

難道C語言對待如此簡單的小學(xué)生都會(huì)做的算術(shù)問題都束手無策嗎?倒也不是這樣,辦法是有的,但需要你自己去想。編程的樂趣大抵在此。

由于本題目問題的核心在于兩個(gè)較大的數(shù)相乘超過了int類型的范圍,所以可以考慮把乘數(shù)拆成較小的數(shù)。比如

123456×654321=123×103+456)×(654×103+321

=123×103×(654×103+321+ 456×(654×103+321

=123×103×654×103+123×103×321+ 456×654×103+ 456×321

=123×654×106+123×321×103+ 456×654×103+ 456×321

=123×654)×106+123×321+ 456×654)×103+ 456×321

如果能分別求出(123×654)、(123×321+ 456×654)、456×321,問題不就解決了嗎?而(123×654)、(123×321+ 456×654)、456×321,可以確信,是可以用int類型表示的。

在這種情況下,用一個(gè)int變量存儲123456654321是不行的,需要兩個(gè),一個(gè)用來記錄123456654321的前三位,另一個(gè)記錄后三位。這種對數(shù)據(jù)的組織和安排方式,就是所謂的數(shù)據(jù)結(jié)構(gòu)。盡管這里的還只是一種很粗糙的數(shù)據(jù)結(jié)構(gòu)。此外還可以發(fā)現(xiàn),設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)首先涉及到的問題恰恰是選擇合適的數(shù)據(jù)類型。

在這種數(shù)據(jù)結(jié)構(gòu)下的算法就是:首先求出(123×654)、(123×321+ 456×654)、456×321?梢詳喽ǚe的最后三位是456×3211000求余的結(jié)果,最前面幾位是(123×654+123×321+ 456×654/103,中間三位的值為(123×321+ 456×654%103+456×321/1000。(這些示意性的東西叫偽代碼(Pseudocode

從對算法的描述中還可以發(fā)現(xiàn),積最好用三個(gè)int來表示。

所以,所謂的算法無非就是對操作步驟的描述。描述算法的方式有很多,其中之一就是使用自然語言來描述。用C語言描述的算法和數(shù)據(jù)結(jié)構(gòu)就是C代碼。

  1. /*編程求123456*654321*/

  2. #include <stdio.h>
  3. #include <stdlib.h>

  4. #define CS1 123456  //乘數(shù)1
  5. #define CS2 654321  //乘數(shù)2
  6. #define YQ  1000    //一千

  7. int main(void)
  8. {
  9. int cs1_q3w,cs1_h3w,cs2_q3w,cs2_h3w;//乘數(shù)1、乘數(shù)2的前3位和后3位
  10. int ji_q,ji_z,ji_h; //積的前、中、后三個(gè)部分
  11.   
  12. cs1_q3w = CS1 / YQ ;
  13. cs1_h3w = CS1 % YQ ;
  14.   
  15. cs2_q3w = CS2 / YQ ;
  16. cs2_h3w = CS2 % YQ ;

  17. //求出(123×654)、(123×321+ 456×654)、456×321
  18. ji_q = cs1_q3w * cs2_q3w ;
  19. ji_z = cs1_q3w * cs2_h3w + cs1_h3w * cs2_q3w ;
  20. ji_h = cs1_h3w * cs2_h3w ;  

  21. //進(jìn)位處理,注意:次序很重要
  22. ji_q = ji_q + ji_z / YQ ;
  23. ji_z = ji_z % YQ + ji_h / YQ ;
  24. ji_h = ji_h % YQ ;
  25. //輸出  
  26. printf("%d×%d == %d%d%d\n" , CS1 , CS2 , ji_q , ji_z ,ji_h );

  27. system("PAUSE");
  28. return 0;
  29. }
復(fù)制代碼

程序輸出

123456×654321 == 80779853376

程序代碼3-5的輸出相比,這個(gè)結(jié)果至少可以說可信度很高,盡管我們還無法確信。

增強(qiáng)對程序正確性信心的方法只有通過測試。由于這段代碼對于兩個(gè)不多于6位的十進(jìn)制數(shù)都應(yīng)該成立,所以可以選擇易于驗(yàn)算的情況運(yùn)行程序,比如把123456改為100000再運(yùn)行程序

然而,很遺憾,程序求100000×654321的結(jié)果竟然是

100000×654321 == 654321000

造成這個(gè)錯(cuò)誤的原因是,代碼中ji_z、ji_h表示的都是三位的十進(jìn)制數(shù),但當(dāng)它們的值為0時(shí),%d這種格式只輸出1個(gè)0而不是3個(gè)0。改進(jìn)的辦法是把它們對應(yīng)的%d改成%03d。其中3表示輸出三位,0表示如果前面有空格則填充0(可以自己上機(jī)對比一下%03d%3d和%d之間的區(qū)別)。

把輸出改寫為

printf("%d×%d == %d%03d%03d\n" , CS1 , CS2 , ji_q , ji_z ,ji_h );
之后,可以發(fā)現(xiàn)程序求100000×654321的結(jié)果是正確的。如果還不放心,可以再找一些數(shù)據(jù)進(jìn)行測試。



作者: cjaizss    時(shí)間: 2011-04-29 08:59
可是在C語言下,好像超過10位就會(huì)溢出啊,怎么解決??
DNFCF 發(fā)表于 2011-04-28 22:57



    大數(shù)運(yùn)算啊
作者: DNFCF    時(shí)間: 2011-04-29 09:38
回復(fù) 20# KBTiller


    恩,看了很受教,弱弱的問下,大數(shù)拆小數(shù)有沒有神馬規(guī)律。?
作者: DNFCF    時(shí)間: 2011-04-29 09:40
回復(fù) 20# KBTiller


      恩,看了很受教,弱弱的問下,大數(shù)拆小數(shù)有沒有神馬規(guī)律。?
作者: KBTiller    時(shí)間: 2011-04-29 11:36
回復(fù)  KBTiller


      恩,看了很受教,弱弱的問下,大數(shù)拆小數(shù)有沒有神馬規(guī)律??
DNFCF 發(fā)表于 2011-04-29 09:40


沒什么規(guī)律
構(gòu)造一個(gè)數(shù)據(jù)結(jié)構(gòu)要結(jié)合具體的算法
最主要的原則我認(rèn)為是能方便地讀寫

你這個(gè)題目
我認(rèn)為可以用一個(gè)數(shù)組來模擬一個(gè)“大數(shù)”(當(dāng)然這不是最精致的方案)
例如
int dashu[22];
用dashu[0]存?zhèn)位數(shù)
用dashu[1]存十位數(shù)
用dashu[2]存百位數(shù)
……
建議你先試一下計(jì)算9^21再輸出(前面有答案便于測試)
作者: koolcoy    時(shí)間: 2011-04-29 12:27
回復(fù) 24# KBTiller


    這種大數(shù)表示方法有些低效{:3_189:}
作者: KBTiller    時(shí)間: 2011-04-29 12:45
回復(fù) 25# koolcoy


    是的。主要考慮到樓主的經(jīng)驗(yàn)不多。
    您的方案是?
作者: koolcoy    時(shí)間: 2011-04-29 13:16
回復(fù) 26# KBTiller

    兩個(gè)64位整數(shù)并做一個(gè)128位整數(shù)使用,或者使用匯編調(diào)使用bcd指令
作者: A.com    時(shí)間: 2011-04-29 13:47
大數(shù)運(yùn)算的基本原理就是進(jìn)制,假設(shè)某個(gè)系統(tǒng)的數(shù)據(jù)寬度為兩位的2進(jìn)制,那么這個(gè)系統(tǒng)對于任何大于3的數(shù)來說,都無法直接運(yùn)算。要想做超過3的運(yùn)算,可以用2個(gè)2位也就是4位來表示數(shù)據(jù),就能處理最大值為15的數(shù)了。所以要做大數(shù)運(yùn)算,只需要再虛擬出一層x進(jìn)制就行了。
作者: KBTiller    時(shí)間: 2011-04-30 09:34
回復(fù)  KBTiller

    兩個(gè)64位整數(shù)并做一個(gè)128位整數(shù)使用,或者使用匯編調(diào)使用bcd指令
koolcoy 發(fā)表于 2011-04-29 13:16



    呵呵,這個(gè)當(dāng)然高效
    不過我估計(jì)樓主只有小米加步槍,不會(huì)有“64位整數(shù)”這種原子彈
作者: KBTiller    時(shí)間: 2011-04-30 13:40
這個(gè)題目的算法其實(shí)不難
從根本上來說考察的是構(gòu)造數(shù)據(jù)的能力
數(shù)據(jù)組織的好,往往并不需要什么精妙的算法
作者: KanonInD    時(shí)間: 2011-05-01 10:00
本帖最后由 KanonInD 于 2011-05-01 17:39 編輯

大數(shù)用 __int128 好了。
http://gcc.gnu.org/onlinedocs/gc ... g_t_005f_005fint128
作者: koolcoy    時(shí)間: 2011-05-01 11:05
這個(gè)題目的算法其實(shí)不難
從根本上來說考察的是構(gòu)造數(shù)據(jù)的能力
數(shù)據(jù)組織的好,往往并不需要什么精妙的算法
KBTiller 發(fā)表于 2011-04-30 13:40


你顯然低估了這個(gè)問題,這個(gè)問題的解空間是10^21。我還沒找到啥號的剪枝辦法{:3_195:}
作者: koolcoy    時(shí)間: 2011-05-01 11:16
這個(gè)問題的難點(diǎn)還是對10^21的解空間的縮小或者dp優(yōu)化。大數(shù)模擬都是小事情
作者: KBTiller    時(shí)間: 2011-05-02 17:01
本帖最后由 KBTiller 于 2011-05-03 10:09 編輯

回復(fù) 32# koolcoy


    確實(shí),我目前還沒想的那么遠(yuǎn),只考慮了樓主的“溢出”問題。但我30樓的觀點(diǎn)不變
    現(xiàn)在看來,10樓A.com 的想法更徹底些
    不過“程序需要循環(huán)21^21次”我覺得是估計(jì)過高了,應(yīng)該是10^19這個(gè)量級
作者: A.com    時(shí)間: 2011-05-02 17:28
本帖最后由 A.com 于 2011-05-02 17:31 編輯

  1. 0                      0
  2. 1                      1
  3. 2                2097152
  4. 3            10460353203
  5. 4          4398046511104
  6. 5        476837158203125
  7. 6      21936950640377856
  8. 7     558545864083284007
  9. 8    9223372036854775808
  10. 9  109418989131512359209
復(fù)制代碼
那么符合條件的數(shù)列里,9出現(xiàn)的頻度在1-9次。而且,末位數(shù)其實(shí)是有規(guī)律的
作者: KBTiller    時(shí)間: 2011-05-02 18:56
末位數(shù)其實(shí)是有規(guī)律的
A.com 發(fā)表于 2011-05-02 17:28

這個(gè)性質(zhì)真有趣
作者: KBTiller    時(shí)間: 2011-05-03 22:07
  1. 449177399146038697307
  2. 128468643043731391252
  3. 請按任意鍵繼續(xù). . .
復(fù)制代碼

用了40多秒
作者: KBTiller    時(shí)間: 2011-05-03 22:15
27907865009977052567814
35452590104031691935943
27879694893054074471405
28361281321319229463398
21887696841122916288858
請按任意鍵繼續(xù). . .
23位
1分40秒
作者: KBTiller    時(shí)間: 2011-05-03 23:02
174088005938065293023722
239313664430041569350093
188451485447897896036875
請按任意鍵繼續(xù). . .
24位
2分27秒
作者: KBTiller    時(shí)間: 2011-05-04 17:41
本帖最后由 KBTiller 于 2011-05-19 09:55 編輯
其實(shí)就是0、1、2097152……9^21的組合,要求組合的和是個(gè)21位的數(shù)字且順序符合。
先湊夠數(shù)字,就是21個(gè)數(shù)之 ...
A.com 發(fā)表于 2011-04-28 17:40


    這個(gè)組合的數(shù)目很少,我計(jì)算的結(jié)果是620309379690  90135045種
--------------------------------------------------------------------
90135045包含了一些充分的組合,還是大了
應(yīng)該是 14139189
作者: koolcoy    時(shí)間: 2011-05-04 23:35
smilence
作者: A.com    時(shí)間: 2011-05-05 17:04
本帖最后由 A.com 于 2011-05-05 17:30 編輯

剛才看到有人說二叉樹不給用遞歸,想起來這個(gè)數(shù)字的變化其實(shí)是可預(yù)期的,譬如把某位的0變成1,那么整個(gè)數(shù)字就是N+1,無論這個(gè)0在什么位置,他變成1的結(jié)果都是相同的。也就是說只有組合相關(guān)性沒有排列相關(guān)性。又因?yàn)檫@21位數(shù)里面至少要有一位是9(沒有9的組合不可能大于10^20),所以實(shí)際需要遍歷的總次數(shù)是10個(gè)數(shù)字的20位組合減去9個(gè)以上9的組合{:3_190:}


最暴力的辦法就是寫就是20層循環(huán),前8層0-9,后12層0-8,最里面別忘了加上一個(gè)9^21。才282529536481次循環(huán)就行了,
作者: KBTiller    時(shí)間: 2011-05-05 18:06
沒有9的組合不可能大于10^20

11 * 8^21= 101,457,092,405,402,533,888
作者: A.com    時(shí)間: 2011-05-06 08:38
11 * 8^21= 101,457,092,405,402,533,888
KBTiller 發(fā)表于 2011-05-05 18:06



    呃,算錯(cuò)了。。{:3_185:}
作者: l2y3n2    時(shí)間: 2011-05-06 20:14
本帖最后由 l2y3n2 于 2011-05-06 20:16 編輯

隨便用Python寫了個(gè)窮舉的,用時(shí)間正好3分鐘、Python自帶的大數(shù)運(yùn)算、程序也沒有優(yōu)化過。
就是窮舉9、8、7、……、0的個(gè)數(shù),然后對比結(jié)果。

用C的話時(shí)間上應(yīng)該還是沒問題的

~$ time ./f.py
449177399146038697307
128468643043731391252

real    2m54.915s
user    2m54.871s
sys     0m0.012s

  1. #! /usr/bin/env python
  2. # -*- coding: UTF-8 -*-

  3. def check(value, nums):
  4.     tmp = [0] * 10
  5.     for c in str(value):
  6.         tmp[ord(c) - ord('0')] += 1
  7.     for i in range(0, 10):
  8.         if tmp[i] != nums[i]:
  9.             return False
  10.     return True


  11. def action(exps, nums, n, leftn, value, idx):
  12.     value += exps[idx] * leftn
  13.     nums[idx] = leftn
  14.     if len(str(value)) < n:
  15.         return

  16.     if (idx == 0):
  17.         if (check(value, nums)):
  18.             print(value)
  19.         return

  20.     for i in range(0, leftn + 1):
  21.         if len(str(value)) <= n:
  22.             action(exps, nums, n, leftn - nums[idx], value, idx - 1)
  23.         value -= exps[idx]
  24.         nums[idx] -= 1


  25. def main(n):
  26.     exps = [i ** n for i in range(0, 10)]
  27.     nums = [0] * 10
  28.     action(exps, nums, n, n, 0, 9)


  29. if __name__ == '__main__':
  30.     main(21)


復(fù)制代碼

作者: oiacm    時(shí)間: 2011-05-13 13:10
用了40多秒
KBTiller 發(fā)表于 2011-05-03 22:07



    想請問你具體怎么做的?我想的是對21位數(shù)進(jìn)行枚舉,但是那樣很崩潰,太慢了
作者: KBTiller    時(shí)間: 2011-05-13 20:32
本帖最后由 KBTiller 于 2011-05-19 10:34 編輯
想請問你具體怎么做的?我想的是對21位數(shù)進(jìn)行枚舉,但是那樣很崩潰,太慢了
oiacm 發(fā)表于 2011-05-13 13:10



    基本是按照10樓的那種思路做的
    只對21位數(shù)的各種組合驗(yàn)算
    提供組合大體上是這樣實(shí)現(xiàn)的

    選擇某位數(shù)字( 1 , 1 );    //選第1位數(shù)字,從1開始


void 選擇某位數(shù)字(const int 第幾位 , const  int 起始的數(shù)字 )
{
    if (  第幾位 >  21  ){
        //驗(yàn)算
        return ;
    }   
    for (int 數(shù)字 = 起始的數(shù)字 ; 數(shù)字 < 10 ; 數(shù)字 ++  ){
        選擇某位數(shù)字 ( 第幾位 + 1 , ( 第幾位 == 1 ? 0 : 數(shù)字 )  ) ;  //第2位及以后各位從0開始選擇  
    }   
}

   就是第一位1~9。第二位及以后都從0開始選數(shù)字,但要保證第二位以后是個(gè)有序的數(shù)字序列

   此外用到了:各個(gè)數(shù)字的21次方事先計(jì)算好,以后查表計(jì)算各個(gè)數(shù)字的21次方的和;9的個(gè)數(shù)不能太多

   我過幾天會(huì)把詳細(xì)的解法寫出來
==============================
這個(gè)有點(diǎn)聰明反被聰明誤了
最初,并沒有考慮第一位不可以為0
但這樣多了一個(gè)21位都為0的情況
為了表達(dá)的更自然
后來改進(jìn)成第一位不能為0
后面各位有序
但這樣實(shí)際上多了若干重復(fù)的組合(見41樓)
作者: 蔡萬釗    時(shí)間: 2011-05-14 02:17
暈死,這里哪有用到乘法啊,分明就只有加法。
作者: 蔡萬釗    時(shí)間: 2011-05-14 02:20
我給個(gè)思路吧。

不用去算數(shù)。

char N[21]

用循環(huán)的方式。

先計(jì)算 21 一個(gè) 1 的結(jié)果,
然后是  20 個(gè) 1 , 一個(gè) 2 ...
依次類推

在每次便利中,尋找一個(gè)可能的 21 個(gè)數(shù)字的排序使得結(jié)合的大叔是一樣大的。

大數(shù)用 long long 就可以表示了吧?
作者: 蔡萬釗    時(shí)間: 2011-05-14 02:21
利用  99 乘法表,直接查表不通過計(jì)算。

暈死,我馬上寫一個(gè),我對這個(gè)數(shù)字的確切大小非常感興趣。
作者: 蔡萬釗    時(shí)間: 2011-05-14 02:38
暈死。 窮舉法都不需要3分鐘就跑出來了

我還以為這3分鐘時(shí)間限制是要多牛逼的算法 ....

看來硬件的發(fā)展還是可以解放腦力的啊
作者: 蔡萬釗    時(shí)間: 2011-05-14 06:02
折騰啊我!!

cai@cai ~/workspace/n21cal $ time ./Debug/n21cal  
1732949 種組合
the number is 128468643043731391252

real        0m11.479s
user        0m11.165s
sys        0m0.268s
作者: 蔡萬釗    時(shí)間: 2011-05-14 06:03
本帖最后由 蔡萬釗 于 2011-05-14 06:32 編輯

  1. /*
  2. ============================================================================
  3. Name        : n21cal.c
  4. Author      :
  5. Version     :
  6. Copyright   : Your copyright notice
  7. Description : Hello World in C, Ansi-style
  8. ============================================================================
  9. */

  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>

  13. typedef struct {
  14.         unsigned long h;
  15.         unsigned long l;
  16. }bignumber;

  17. bignumber table[10]={
  18.                 {0,0},
  19.                 {0UL,1UL},
  20.                 {0UL,2097152UL},
  21.                 {0UL,10460353203UL},
  22.                 {0UL,4398046511104UL},
  23.                 {0UL,476837158203125UL},
  24.                 {0UL,21936950640377856UL},
  25.                 {0UL,558545864083284007UL},
  26.                 {0UL,9223372036854775808UL},

  27.                 {0x5UL,0xEE7E56E3721F2929UL},

  28. };

  29. bignumber del(bignumber a, bignumber b)
  30. {
  31.         bignumber c= {0,0};
  32.         c.l = a.l - b.l;

  33.         if(a.l < b.l )
  34.         {
  35.                 a.h --;
  36. //                c.l++;
  37.         }

  38.         c.h = a.h - b.h;

  39.         return c;
  40. }

  41. bignumber add(bignumber a, bignumber b)
  42. {
  43.         bignumber c= {0,0};

  44.         c.l = a.l + b.l;

  45.         if( ( (-1UL) - a.l ) < b.l)
  46.                 c.h ++;
  47.         c.h += a.h + b.h;

  48.         return c;
  49. }


  50. //獲得對應(yīng)的數(shù)字
  51. bignumber get_table( int i)
  52. {

  53.         return table[i];

  54. }

  55. bignumber get_n_i(int b , int i )
  56. {
  57.         bignumber c = {0};
  58.         for(; i >0 ; i--)
  59.                 c = add(c , get_table(b));
  60.         return c;
  61. }

  62. int inline mylog2( unsigned long x)
  63. {
  64.         int i;

  65.         static unsigned long logtable[64] ={
  66.                         0x8000000000000000,
  67.                         0x4000000000000000,
  68.                         0x2000000000000000,
  69.                         0x1000000000000000,
  70.                         0x800000000000000,
  71.                         0x400000000000000,
  72.                         0x200000000000000,
  73.                         0x100000000000000,
  74.                         0x80000000000000,
  75.                         0x40000000000000,
  76.                         0x20000000000000,
  77.                         0x10000000000000,
  78.                         0x8000000000000,
  79.                         0x4000000000000,
  80.                         0x2000000000000,
  81.                         0x1000000000000,
  82.                         0x800000000000,
  83.                         0x400000000000,
  84.                         0x200000000000,
  85.                         0x100000000000,
  86.                         0x80000000000,
  87.                         0x40000000000,
  88.                         0x20000000000,
  89.                         0x10000000000,
  90.                         0x8000000000,
  91.                         0x4000000000,
  92.                         0x2000000000,
  93.                         0x1000000000,
  94.                         0x800000000,
  95.                         0x400000000,
  96.                         0x200000000,
  97.                         0x100000000,
  98.                         0x80000000,
  99.                         0x40000000,
  100.                         0x20000000,
  101.                         0x10000000,
  102.                         0x8000000,
  103.                         0x4000000,
  104.                         0x2000000,
  105.                         0x1000000,
  106.                         0x800000,
  107.                         0x400000,
  108.                         0x200000,
  109.                         0x100000,
  110.                         0x80000,
  111.                         0x40000,
  112.                         0x20000,
  113.                         0x10000,
  114.                         0x8000,
  115.                         0x4000,
  116.                         0x2000,
  117.                         0x1000,
  118.                         0x800,
  119.                         0x400,
  120.                         0x200,
  121.                         0x100,
  122.                         0x80,
  123.                         0x40,
  124.                         0x20,
  125.                         0x10,
  126.                         0x8,
  127.                         0x4,
  128.                         0x2,
  129.                         0x1,
  130.         };

  131.         for( i  = 0 ; i < 64 ; i++)
  132.         {
  133.                 if (x & logtable[i]) return i;
  134.         }
  135.         return -1;
  136. }

  137. bignumber  dvi_10(bignumber a)
  138. {
  139.         bignumber t;
  140.         int tmp = mylog2(a.h);

  141.         t.h  = ((a.h << tmp) | a.l >> ( 64 - tmp)) / 10 ;

  142.         unsigned long yu = ((a.h << tmp) | a.l >> ( 64 - tmp)) % 10;

  143.         t.l = (((a.l << tmp )>> tmp) | (yu << (64 - tmp))) / 10;

  144.         tmp = mylog2(t.l);

  145.         a.h = t.h >> tmp;

  146.         a.l = t.l | ( t.h <<  (  64 - tmp  )) ;

  147.         return a;
  148. }

  149. void inline revstr(char *str)
  150. {   //省去一變量, 時(shí)間換空間法
  151.     char *head = str, *tail = str + strlen(str) -1;
  152.     for(; head < tail; *head=*head ^ *tail, *tail=*head ^ *tail, *head=*head++ ^ *tail--);
  153. }


  154. void inline to_str(bignumber n, char N[22])
  155. {
  156.         //基本原理是,
  157. //        尋找個(gè)位,然后 除以 10
  158. //        繼續(xù)
  159.         int cur=0;

  160.         do{
  161.                 bignumber n3=n,n2 = dvi_10(n);

  162.                 n3 = del(n3,n2);
  163.                 n3 = del(n3,n2);
  164.                 n3 = del(n3,n2);
  165.                 n3 = del(n3,n2);
  166.                 n3 = del(n3,n2);

  167.                 n3 = del(n3,n2);
  168.                 n3 = del(n3,n2);
  169.                 n3 = del(n3,n2);
  170.                 n3 = del(n3,n2);
  171.                 n3 = del(n3,n2);

  172.                 N[cur++] = '0' + n3.l;

  173.                 n = n2;

  174.         }while( n.h  || n.l   );

  175.         revstr(N);


  176. }

  177. int inline charcnt(const char *ptr, unsigned char ch)
  178. {
  179.     int count = 0;
  180.     while(*ptr)
  181.     {
  182.                if(ch == *ptr)
  183.                {
  184.                      count++;
  185.                }
  186.                ptr++;
  187.     }
  188.     return count;
  189. }



  190. int main(void)
  191. {
  192.         char  N[22]="";

  193.         int n0,n1,n2,n3,n4,n5,n6,n7,n8,n9;

  194.         for(n9 = 1 ; n9 <= 21 ; n9++)
  195.                 for(n8 = 0 ; n8 <= 21 - n9 ; n8++)
  196.                         for(n7 = 0 ; n7 <= 21 -n9 - n8 ; n7++)
  197.                                 for(n6 = 0 ; n6 <= 21 -n9 - n8 -n7 ; n6++)
  198.                                         for(n5 = 0 ; n5 <= 21 -n9 - n8 -n7 -n6; n5++)
  199.                                                 for(n4 = 0 ; n4 <= 21 -n9 - n8 -n7 -n6 -n5 ; n4++)
  200.                                                         for(n3 = 0 ; n3 <= 21 -n9 - n8 -n7 -n6 -n5 -n4 ; n3++)
  201.                                                                 for(n2 = 0 ; n2 <= 21 -n9 - n8 -n7 -n6 -n5 -n4 -n3; n2++)
  202.                                                                         for(n1 = 0 ; n1 <= 21  -n9 - n8 -n7 -n6 -n5 -n4 -n3 -n2; n1++)
  203.                                                                         {
  204.                                                                                 n0 = 21 - n9 - n8 - n7 - n6 - n5 - n4
  205.                                                                                                 - n3 - n2 - n1;

  206.                                                                                 bignumber sum = { 0 };

  207.                                                                                 sum.l = n1;
  208.                                                                                 sum = add(sum, get_n_i(2, n2));
  209.                                                                                 sum = add(sum, get_n_i(3, n3));
  210.                                                                                 sum = add(sum, get_n_i(4, n4));
  211.                                                                                 sum = add(sum, get_n_i(5, n5));
  212.                                                                                 sum = add(sum, get_n_i(6, n6));
  213.                                                                                 sum = add(sum, get_n_i(7, n7));
  214.                                                                                 sum = add(sum, get_n_i(8, n8));
  215.                                                                                 sum = add(sum, get_n_i(9, n9));

  216.                                                                                 static long loop;

  217.                                                                                 ++loop;

  218.                                                                                 if(sum.h <= 4)
  219.                                                                                         continue;

  220.                                                                                 //開始校驗(yàn)

  221. //                                                                                轉(zhuǎn)化為字符串

  222.                                                                                 to_str(sum, N );

  223. //                                                                                統(tǒng)計(jì) 0 1 2 3 4 5 6 7 8 9 的個(gè)數(shù)

  224.                                                                                 if(charcnt(N,'9') == n9)
  225.                                                                                         if(charcnt(N,'8') == n8)
  226.                                                                                                 if(charcnt(N,'7') == n7)
  227.                                                                                                         if(charcnt(N,'6') == n6)
  228.                                                                                                                 if(charcnt(N,'5') == n5)
  229.                                                                                                                         if(charcnt(N,'4') == n4)
  230.                                                                                                                                 if(charcnt(N,'3') == n3)
  231.                                                                                                                                         if(charcnt(N,'2') == n2)
  232.                                                                                                                                                 if(charcnt(N,'1') == n1)
  233.                                                                                                                                                
  234.                                                                                                                                                 {
  235.                                                                                                                                                                 printf("%ld 種組合\n", loop);

  236.                                                                                                                                                                 printf("the number is %s\n", N);
  237.                                                                                                                                                 }

  238.                                                                                 memset(N,0,22);
  239.                                                                         }




  240.         return EXIT_SUCCESS;
  241. }

復(fù)制代碼

作者: 蔡萬釗    時(shí)間: 2011-05-14 06:05
我真 TM 有功夫折騰啊! 居然折騰了這么久。
對 KBTiller 表示佩服。
作者: 蔡萬釗    時(shí)間: 2011-05-14 06:36
奇怪,怎么算都只有一個(gè)結(jié)果的。。! 為何我的只能那個(gè)算出一個(gè)結(jié)果來!。!
作者: KBTiller    時(shí)間: 2011-05-14 09:22
回復(fù) 55# 蔡萬釗


    一夜就弄出來了,你寫得比我快多了
作者: KBTiller    時(shí)間: 2011-05-14 09:23
本帖最后由 KBTiller 于 2011-05-14 09:38 編輯
我給個(gè)思路吧。

不用去算數(shù)。

char N[21]

用循環(huán)的方式。

先計(jì)算 21 一個(gè) 1 的結(jié)果,
然后是  20 個(gè) 1 , 一個(gè) 2 ...
依次類推

  ...
蔡萬釗 發(fā)表于 2011-05-14 02:20

這個(gè)循環(huán)嵌套的深度少
更好
作者: 蔡萬釗    時(shí)間: 2011-05-15 02:36
這個(gè)循環(huán)嵌套的深度少
更好
KBTiller 發(fā)表于 2011-05-14 09:23



    還是嵌套了9層呢!
作者: KBTiller    時(shí)間: 2011-05-15 10:49
回復(fù) 59# 蔡萬釗


    已經(jīng)好多了,我那個(gè)嵌套21層
作者: KBTiller    時(shí)間: 2011-05-16 08:55
回復(fù) 54# 蔡萬釗


    for(n9 = 1 ; n9 <= 21 ; n9++)

n9 是9的個(gè)數(shù)嗎?如果是的話,這里值得推敲
作者: KBTiller    時(shí)間: 2011-05-16 09:05
本帖最后由 KBTiller 于 2011-05-16 09:18 編輯
折騰啊我!!

cai@cai ~/workspace/n21cal $ time ./Debug/n21cal  
1732949 種組合
the number is 12 ...
蔡萬釗 發(fā)表于 2011-05-14 06:02


我用類似你的想法做,組合數(shù)比你這個(gè)高一個(gè)量級 ,14139189
作者: leeews    時(shí)間: 2011-05-16 13:17
確實(shí)變態(tài)
作者: KBTiller    時(shí)間: 2011-05-16 14:45
我給個(gè)思路吧。

不用去算數(shù)。

char N[21]

用循環(huán)的方式。

先計(jì)算 21 一個(gè) 1 的結(jié)果,
然后是  ...
蔡萬釗 發(fā)表于 2011-05-14 02:20



    按你的辦法改進(jìn)了一下,增加了從小到大輸出的功能,不到40秒
    你的辦法真不錯(cuò)


128468643043731391252
449177399146038697307
請按任意鍵繼續(xù). . .

作者: KBTiller    時(shí)間: 2011-05-16 14:48
想請問你具體怎么做的?我想的是對21位數(shù)進(jìn)行枚舉,但是那樣很崩潰,太慢了
oiacm 發(fā)表于 2011-05-13 13:10



    容我稍微整理一下,很快就會(huì)發(fā)出來
作者: 蔡萬釗    時(shí)間: 2011-05-17 00:26
回復(fù) 61# KBTiller

是。貌似有人說要至少 一個(gè)9 , 沒9 是不行的 ~~~

就這樣寫了。

問題是怎么算都只有一個(gè)結(jié)果,而不是2個(gè),一定是哪里漏了。
作者: KBTiller    時(shí)間: 2011-05-17 00:36
回復(fù) 66# 蔡萬釗

“至少 一個(gè)9 , 沒9 是不行的”,這個(gè)不對

n9應(yīng)該是 0~9 個(gè),可以沒有,最多9個(gè)
作者: 蔡萬釗    時(shí)間: 2011-05-17 00:46
回復(fù) 67# KBTiller


    好,我修改一下看看。
作者: 蔡萬釗    時(shí)間: 2011-05-17 00:55
回復(fù) 67# KBTiller


    不行啊! 還是只有一個(gè)結(jié)果。莫非是我的大數(shù)的計(jì)算錯(cuò)誤了?
作者: KBTiller    時(shí)間: 2011-05-17 08:50
回復(fù)  KBTiller


    不行! 還是只有一個(gè)結(jié)果。莫非是我的大數(shù)的計(jì)算錯(cuò)誤了?
蔡萬釗 發(fā)表于 2011-05-17 00:55


    用 n9 = 4,n8 = 1,n7 = 4
        n6 = 2,n5 = 0,n4 = 3
        n3 = 3,n2 = 0,n1 = 2
        n0 = 2。(449177399146038697307 )試一下,也許能發(fā)現(xiàn)bug

   你的機(jī)器sizeof(unsigned long)是多少?我的機(jī)器上試不起來
作者: KBTiller    時(shí)間: 2011-05-17 12:09
獻(xiàn)丑!請大家指正

0_問題.h

  1. /*
  2. 一個(gè)N位的十進(jìn)制正整數(shù),如果它的每個(gè)位上的數(shù)字的N次方的和等于這個(gè)數(shù)本身,
  3. 則稱其為花朵數(shù)。
  4. 例如:
  5. 當(dāng)N=3時(shí),153就滿足條件,因?yàn)?1^3 + 5^3 + 3^3 = 153,
  6. 這樣的數(shù)字也被稱為水仙花數(shù)(其中,“^”表示乘方,5^3表示5的3次方,也就是立方)。
  7. 當(dāng)N=4時(shí),1634滿足條件,因?yàn)?1^4 + 6^4 + 3^4 + 4^4 = 1634。
  8. 當(dāng)N=5時(shí),92727滿足條件。
  9. 實(shí)際上,對N的每個(gè)取值,可能有多個(gè)數(shù)字滿足條件。
  10. 程序的任務(wù)是:求N=21時(shí),所有滿足條件的花朵數(shù)。注意:這個(gè)整數(shù)有21位,
  11. 它的各個(gè)位數(shù)字的21次方之和正好等于這個(gè)數(shù)本身。
  12. 如果滿足條件的數(shù)字不只有一個(gè),請從小到大輸出所有符合條件的數(shù)字,
  13. 每個(gè)數(shù)字占一行。因?yàn)檫@個(gè)數(shù)字很大,
  14. 請注意解法時(shí)間上的可行性。要求程序在3分鐘內(nèi)運(yùn)行完畢。
  15. */
  16. #ifndef WENTI_H
  17. #define WENTI_H
  18.     #define CESHI        //進(jìn)行測試  
  19.     //#define QIUJIE     //求解21位問題                              
  20.    
  21.     #ifdef CESHI             //測試
  22.       #define JINZHI 10      //十進(jìn)制
  23.       #define WEISHU 3       //3位花朵數(shù)   
  24.       #define N      WEISHU  //冪次==位數(shù)
  25.     #endif //CESHI_3
  26.    
  27.     #ifdef QIUJIE            //求解            
  28.       #define JINZHI 10      //十進(jìn)制
  29.       #define WEISHU 21      //位數(shù)   
  30.       #define N      WEISHU  //冪次==位數(shù)
  31.     #endif //QIUJIE
  32.    
  33. #endif // WENTI_H
  34. /*
  35. 注:
  36. 通過修改符號常量的值,可以得到其他進(jìn)制或其他位數(shù)花朵數(shù)問題的解
  37. */

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:11
1_MAIN_type.h


  1. #ifndef MAIN_T_H
  2. #define MAIN_T_H
  3.     //NOTHING
  4. #endif // MAIN_T_H

復(fù)制代碼


1_MAIN_function.h


  1. #ifndef MAIN_F_H
  2. #define MAIN_F_H
  3.     #include "1_MAIN_type.h"      
  4.     #include "2_數(shù)字組合_function.h"  //zuhe_sz()及參數(shù)
  5.     #include "5_處理結(jié)果_function.h"  //shuchu_jg()
  6.     #include <stdlib.h>               //system()
  7.      
  8. #endif // MAIN_F_H

復(fù)制代碼


1_MAIN.c

  1. /*
  2.   Name:花朵數(shù)問題
  3.   Author: 鍵盤農(nóng)夫
  4.   Date: 17-05-11
  5.   Description: 一個(gè)一般性解法,
  6.                適用其他進(jìn)制(<=10)、其他位數(shù)的花朵數(shù)求解
  7. */
  8. #include "1_MAIN_function.h"
  9. #define ANY 0
  10. int main( void )
  11. {
  12.     zuhe_sz( ZHUNBEI , ANY );    //進(jìn)行數(shù)字組合<=>驗(yàn)算<=>存儲結(jié)果
  13.            //第一個(gè)實(shí)參為ZHUNBEI時(shí),第二個(gè)實(shí)參沒有用處
  14.     shuchu_jg();                 //輸出結(jié)果,釋放內(nèi)存   
  15.     system("PAUSE");
  16.     return 0;
  17. }
  18. #undef ANY
  19. /*
  20. 注:稍微修改一下輸出的函數(shù)shuchu(),程序也適合10以上進(jìn)制
  21. */

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:13
本帖最后由 KBTiller 于 2011-05-18 11:12 編輯

2_數(shù)字組合_type.h


  1. #ifndef ZUHE_T_H
  2. #define ZUHE_T_H
  3.     #include "3_組合驗(yàn)算_type.h"      
  4.     #include "0_問題.h"
  5. #endif // ZUHE_T_H

復(fù)制代碼


2_數(shù)字組合_function.h


  1. #ifndef ZUHE_F_H
  2. #define ZUHE_F_H
  3.     #include "2_數(shù)字組合_type.h"
  4.     #include "3_組合驗(yàn)算_function.h"   
  5.     #include "4_大數(shù)運(yùn)算_function.h"      
  6.       
  7.     extern void zuhe_sz( const int , const int );
  8.     //zuhe_sz()的兩個(gè)特殊參數(shù)
  9.         #define ZHUNBEI   JINZHI
  10.         #define WANCHENG  0
  11. #endif // ZUHE_F_H

復(fù)制代碼


2_數(shù)字組合.c


  1. #include "2_數(shù)字組合_function.h"
  2. //求"WEISU位數(shù)"的各種數(shù)字組合
  3. //sz:某一數(shù)字,gs:該數(shù)字可能選擇的最大個(gè)數(shù)
  4. //sz: ZHUNBEI 進(jìn)行必要準(zhǔn)備
  5. //sz: WANCHENG 組合完成(可以確定0的個(gè)數(shù)時(shí))
  6. extern void zuhe_sz( const int sz , const  int gs )
  7. {
  8.     static SHUZI_GESHU_t sj_gs , //實(shí)際的個(gè)數(shù)
  9.                          gs_sx ; //個(gè)數(shù)的上限
  10.    
  11.     switch ( sz ) {
  12.         case  ZHUNBEI:
  13.                       jisuan_zhunbei( & gs_sx );   //計(jì)算準(zhǔn)備
  14.                       zuhe_sz ( sz - 1 , WEISHU ) ;
  15.                       qing0( & gs_sx );            //對 gs_sx清0                     
  16.                       break;
  17.         default      :  //嘗試某數(shù)字(sz)的各種可能的數(shù)目(i)
  18.                       {
  19.                           int i ;
  20.                           for ( i =  0 ;
  21.                                 i <= ( (gs < gs_sx[sz]) ? gs : gs_sx[sz] ) ;
  22.                                 i ++  ){
  23.                               sj_gs [ sz ] = i ;
  24.                               zuhe_sz ( sz - 1 , gs - i ) ; //下一個(gè)數(shù)字
  25.                               sj_gs [ sz ] = 0 ;
  26.                           }
  27.                       }                        
  28.                       break;
  29.         case WANCHENG:   
  30.                       sj_gs [ sz ] = gs  ;         //0的個(gè)數(shù)  
  31.                       jianyan( &sj_gs )  ;         //對數(shù)字組合驗(yàn)算
  32.                       sj_gs [ sz ] = 0   ;            
  33.                       break;
  34.     }                     
  35. }

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:15
3_組合驗(yàn)算_type.h


  1. #ifndef YANSUAN_T_H
  2. #define YANSUAN_T_H
  3.     #include "0_問題.h"
  4.     #include "6_常用.h"   
  5.     #include "4_大數(shù)運(yùn)算_type.h"        
  6.     typedef int     SHUZI_GESHU_t[JINZHI]   ;   //描述各個(gè)數(shù)字出現(xiàn)個(gè)數(shù)的類型
  7.     // 0的個(gè)數(shù),1的個(gè)數(shù)……JINZHI-1的個(gè)數(shù)     
  8. #endif // YANSUAN_T_H

復(fù)制代碼


3_組合驗(yàn)算_function.h


  1. #ifndef YANSUAN_F_H
  2. #define YANSUAN_F_H
  3.     #include "3_組合驗(yàn)算_type.h"      
  4.    
  5.     #include "4_大數(shù)運(yùn)算_function.h"         
  6.     #include "5_處理結(jié)果_function.h"         
  7.          
  8.     extern void jisuan_zhunbei( SHUZI_GESHU_t * );
  9.     extern void qing0  ( SHUZI_GESHU_t * )  ;
  10.     extern void jianyan( SHUZI_GESHU_t * )  ;
  11. #endif // YANSUAN_F_H

復(fù)制代碼


3_組合驗(yàn)算.c


  1. #include "3_組合驗(yàn)算_function.h"   
  2. static DASHU_t sjb[JINZHI][WEISHU]; //數(shù)據(jù)表   
  3. //////         1*0^N,2*0^N,……WEISHU*0^N
  4. //////         1*1^N,2*1^N,……WEISHU*1^N
  5. //////         1*2^N,2*2^N,……WEISHU*2^N
  6. //////         ……
  7. //////         1*9^N,2*9^N,……WEISHU*9^N   
  8. //////================================================
  9. //檢驗(yàn)構(gòu)成組合的各個(gè)數(shù)字的N次方之和的數(shù)字組合
  10. //是否與原來的組合一致
  11. extern void jianyan( SHUZI_GESHU_t * p_zhsm )
  12. {
  13.     DASHU_t he ;
  14.     fuzhi ( & he , 0 ) ;  //初值為0
  15.     int i ;
  16.     for( i = 1; i < GESHU(sjb) ; i++){ //i=1, 0的N次冪不用加
  17.        if ( (* p_zhsm)[i] == 0 )           //某數(shù)字不出現(xiàn)
  18.            continue ;   
  19.        jiaru( & he , sjb[i] + (( * p_zhsm )[i] - 1)  ); // 求和
  20.     }
  21.    
  22.     if(  chaoguo_ws ( & he ) == SHI
  23.       || bugou_ws   ( & he ) == SHI  )     //位數(shù)不符合
  24.        return ;
  25.    
  26.     if ( xiangtong ( & he , p_zhsm ) == FOU )//和的組合與原來的組合不同
  27.         return ;         
  28.    
  29.     jilu_jg( &he );
  30. }
  31. //求各個(gè)數(shù)字的N次方及其整數(shù)倍(1,2,……WEISHU倍)
  32. //同時(shí)求出各個(gè)數(shù)字出現(xiàn)次數(shù)的上限存入 * p_zhsx
  33. extern void jisuan_zhunbei( SHUZI_GESHU_t * p_zhsx )
  34. {
  35.     int hang , lie ;
  36.    
  37.     for ( hang = 0 ; hang < GESHU( sjb ) ; hang++ ){
  38.         
  39.         qiu_mi ( sjb[hang]  , hang , N  ) ;     //求i的N次冪
  40.         
  41.         for ( lie = 1 ; lie < GESHU( sjb[hang] ) ; lie ++  ) { //WEISHU
  42.             cheng ( sjb[hang] + lie    , sjb[hang]   , lie + 1 ) ;
  43.             
  44.             if ( chaoguo_ws ( sjb[hang] + lie ) == SHI ) //結(jié)果超過WEISHU
  45.                 break ;   
  46.         }   
  47.         (* p_zhsx)[hang] = lie  ;    // 某數(shù)字出現(xiàn)次數(shù)的上限值
  48.     }
  49. }
  50. extern void qing0( SHUZI_GESHU_t * p_zhsx )
  51. {
  52.     int *p = * p_zhsx ;
  53.     while ( p < * ( p_zhsx + 1 ))
  54.         *p++ = 0 ;
  55. }

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:17
4_大數(shù)運(yùn)算_type.h


  1. #ifndef DASHU_T_H
  2. #define DASHU_T_H
  3.     #include "0_問題.h"
  4.     #include "6_常用.h"
  5.     #include "3_組合驗(yàn)算_type.h"
  6.     typedef int DASHU_t[WEISHU] ; //大數(shù)類型
  7.    
  8. #endif // DASHU_T_H

復(fù)制代碼


4_大數(shù)運(yùn)算_function.h


  1. #ifndef DASHU_F_H
  2. #define DASHU_F_H
  3.     #include "4_大數(shù)運(yùn)算_type.h"
  4.    
  5.     #include <stdio.h>
  6.     #include "3_組合驗(yàn)算_function.h"   
  7.         
  8.     extern void qiu_mi ( DASHU_t * const , const int , int  ) ;
  9.     extern void fuzhi  ( DASHU_t * const , const int ) ;
  10.     extern void cheng  ( DASHU_t * const , DASHU_t * const , const int );
  11.     extern void jiaru  ( DASHU_t * const ,  DASHU_t * const );
  12.     extern void shuchu ( DASHU_t * const );
  13.     extern void copy_ds( DASHU_t * const , DASHU_t * const ) ;
  14.     extern SF   xiaoyu     ( DASHU_t * const , DASHU_t * const ) ;
  15.     extern SF   chaoguo_ws ( DASHU_t * const ) ;
  16.     extern SF   bugou_ws   ( DASHU_t * const ) ;
  17.     extern SF   xiangtong  (  DASHU_t * const  ,  SHUZI_GESHU_t * const ) ;
  18. #endif // DASHU_F_H

復(fù)制代碼

4_大數(shù)運(yùn)算.c


  1. #include "4_大數(shù)運(yùn)算_function.h"
  2. extern  void shuchu(  DASHU_t * const p_ds )
  3. {
  4.     int *w = *p_ds , *t = *(p_ds+1) -1;
  5.     int i;
  6.    
  7.     while( t > w && *t == 0) //前面的0不輸出
  8.        t--;  
  9.    
  10.     for ( i = t - w ; i >= 0 ; i-- )
  11.        printf("%d" , w[i]);
  12.     putchar('\n');
  13. }
  14. extern void copy_ds ( DASHU_t * const p_zd, DASHU_t * const p_qd )
  15. {
  16.     int i ;
  17.     for (i = 0 ; i < GESHU(*p_zd) ; i++ )
  18.         (*p_zd)[i] = (*p_qd)[i] ;
  19. }
  20. //判斷*p_he的組合是否與*p_szzh相同
  21. SF xiangtong ( DASHU_t * const p_he ,  SHUZI_GESHU_t * const p_szzh )
  22. {
  23.     SHUZI_GESHU_t szgs ;
  24.     int i ;
  25.     qing0  ( & szgs ) ;
  26.     for (i = 0 ; i < GESHU(*p_he) ; i++ )
  27.         szgs[(*p_he)[i]]++;
  28.    
  29.     for(i=0;i<GESHU(szgs);i++)
  30.         if(szgs[i]!=((*p_szzh)[i]))
  31.             return FOU ;
  32.         
  33.     return SHI;
  34. }
  35. //進(jìn)位
  36. static void jinwei( DASHU_t * const p_ds)
  37. {
  38.     int *q = *p_ds ;
  39.     while ( q < *( p_ds + 1) - 1 ){
  40.         * ( q + 1 ) += * q / JINZHI ;
  41.         * q++ %= JINZHI ;
  42.     }   
  43. }
  44. //小于
  45. extern SF xiaoyu  ( DASHU_t * const p_ds1 , DASHU_t * const p_ds2 )
  46. {
  47.     int i;
  48.     for( i = GESHU(*p_ds1) - 1 ; i >= 0 ; i -- ){
  49.         if( (*p_ds1)[i]<(*p_ds2)[i] )
  50.             return SHI ;
  51.         if( (*p_ds1)[i]>(*p_ds2)[i] )
  52.             return FOU ;
  53.     }
  54.     return FOU ;   
  55. }
  56. //將*p_js累加入*p_he
  57. extern void jiaru( DASHU_t * const p_he ,  DASHU_t * const p_js)
  58. {
  59.     int i;
  60.     for(i=0;i<GESHU(*p_he);i++)
  61.         (*p_he)[i] += (*p_js)[i];
  62.         
  63.     jinwei(p_he) ;
  64. }
  65. //判斷是否超過WEISHU
  66. extern SF chaoguo_ws ( DASHU_t * const p_ds )
  67. {
  68.     if( p_ds[1][-1] >= JINZHI ){
  69.         return SHI ;
  70.     }
  71.     return FOU;
  72. }
  73. //判斷是否位數(shù)不到WEISHU
  74. extern SF bugou_ws ( DASHU_t * const p_ds )
  75. {
  76.     if( p_ds[1][-1] == 0 )
  77.         return SHI ;
  78.     return FOU;
  79. }
  80. //cs2*(*p_cs1)=>(*p_ji)
  81. extern void cheng ( DASHU_t * const p_ji , DASHU_t * const p_cs1 , const int cs2)
  82. {
  83.    int *p = *p_ji ,*q = *p_cs1;
  84.    while ( p < * ( p_ji + 1) )
  85.         *p++ = *q++ * cs2 ;
  86.    
  87.    //進(jìn)位
  88.    jinwei( p_ji );   
  89. }
  90. //求i的n次冪,放在 * p_ds 中
  91. extern void qiu_mi ( DASHU_t * const p_ds , const int i , int  n  )
  92. {
  93.     fuzhi ( p_ds , i ) ;
  94.     while ( --n > 0 )
  95.         cheng ( p_ds , p_ds , i);
  96. }
  97. //賦值,大于JINZHI的數(shù)也可以
  98. extern  void fuzhi ( DASHU_t * const p_ds , const int i )
  99. {
  100.     int *q = *p_ds ;
  101.     *q = i ;
  102.     while ( q < *( p_ds + 1) - 1){
  103.         * ( q + 1 ) = * q / JINZHI ;
  104.         * q++ %= JINZHI ;
  105.     }
  106. }

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:19
5_處理結(jié)果_type.h


  1. #ifndef JIEGUO_T_H
  2. #define JIEGUO_T_H

  3.    
  4.     #include "0_問題.h"
  5.     #include "4_大數(shù)運(yùn)算_type.h"
  6.     typedef struct JD{
  7.                       DASHU_t ds   ;  //大數(shù)
  8.                       struct JD *xyg ;//下一個(gè)
  9.                      } JIEDIAN_t ;      //節(jié)點(diǎn)類型
  10.     typedef JIEDIAN_t *TOU_t  ;         //頭類型
  11. #endif // JIEGUO_T_H

復(fù)制代碼

5_處理結(jié)果_function.h

  1. #ifndef JIEGUO_F_H
  2. #define JIEGUO_F_H
  3.     #include "5_處理結(jié)果_type.h"
  4.    
  5.     #include "4_大數(shù)運(yùn)算_function.h"      
  6.     #include <stdio.h>
  7.     #include <stdlib.h>
  8.         
  9.     extern void jilu_jg( DASHU_t * );
  10.     extern void shuchu_jg ( void );
  11.    
  12. #endif // JIEGUO_F_H

復(fù)制代碼

5_處理結(jié)果.c


  1. #include "5_處理結(jié)果_function.h"
  2. static TOU_t tou = NULL ;
  3. static void jia_jd ( TOU_t ,TOU_t *);
  4. static void shifang_nc(TOU_t);
  5. static void shifang_nc( TOU_t p )
  6. {
  7.     TOU_t q  ;
  8.     if( p == NULL )
  9.         return ;
  10.    
  11.     q = p->xyg ;
  12.     free(p);
  13.     shifang_nc( q );
  14. }
  15. extern void jilu_jg( DASHU_t * p_ds )
  16. {
  17.     TOU_t p_jd ;
  18.     if( (p_jd = malloc( sizeof (JIEDIAN_t )) ) == NULL ){
  19.         shifang_nc( tou );
  20.         puts("無法記錄結(jié)果,程序退出");
  21.         exit ( ! EXIT_SUCCESS ) ;
  22.     }
  23.    
  24.     copy_ds ( & p_jd->ds  , p_ds ) ;   //復(fù)制
  25.     jia_jd ( p_jd , & tou );           //加入鏈表(p_jd,tou)
  26. }
  27. //按照一定次序加入節(jié)點(diǎn)
  28. static void jia_jd ( TOU_t  xjd, TOU_t  *p_xyg  )
  29. {
  30.     if( *p_xyg == NULL ||
  31.         ( xiaoyu ( & xjd -> ds , &(*p_xyg)->ds )) == SHI ){/* 小于 */
  32.         xjd->xyg = *p_xyg ;
  33.         *p_xyg = xjd ;
  34.         return ;
  35.     }
  36.     jia_jd ( xjd  , &(*p_xyg)->xyg ) ;
  37. }
  38. //輸出結(jié)果,之后釋放內(nèi)存
  39. extern void shuchu_jg( void )
  40. {
  41.     TOU_t temp = tou ;
  42.     while ( temp != NULL ){
  43.         shuchu(&temp->ds);
  44.         temp = temp->xyg ;
  45.     }   
  46.     shifang_nc( tou );   
  47.     tou = NULL ;
  48. }

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:21
6_常用.h


  1. //我編程常用的成語和俚語
  2. #ifndef CHANGYONG_H
  3. #define CHANGYONG_H
  4.     typedef enum { FOU , SHI } SF ;
  5.    
  6.     #define GESHU(A) ((sizeof (A)) / (sizeof (*(A))) )
  7.    
  8. #endif // CHANGYONG_H

復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-17 12:35
從蔡萬釗、A.com、koolcoy (娶妻求賢)網(wǎng)友的發(fā)言中受到了許多啟發(fā),在此致謝!
作者: koolcoy    時(shí)間: 2011-05-17 14:26
好多年沒看過用拼音寫的程序了,怎么看怎么囧,有空了再來研究{:3_196:}
作者: 蔡萬釗    時(shí)間: 2011-05-17 20:30
回復(fù) 70# KBTiller


    我是 AMD64 的 Gentoo 系統(tǒng)。
作者: koolcoy    時(shí)間: 2011-05-18 10:31
昨晚想了一下這個(gè)問題,有這么一個(gè)優(yōu)化方法:
將1^21 * 1, 1^21 * 2, 1^21 * 3 ... 1^21 * 21, 2^21 * 1, 2^21 * 2 ... 2^21 * 21, .... 9^21 * 21一共189個(gè)數(shù)保存起來。于是原問題抓換成從這189個(gè)數(shù)中選最多9個(gè)數(shù)出來,使得他們的和滿足一定的條件。整個(gè)問題的解空間小于21^9 ,這個(gè)數(shù)字大概是5000億,采用深搜,再根據(jù)位數(shù)為21這個(gè)條件剪一下枝,最終的解空間應(yīng)該不會(huì)超過100億。

這種算法的復(fù)雜度是O(N^9),而不是O(9^N),N為位數(shù)。
作者: KBTiller    時(shí)間: 2011-05-18 10:50
本帖最后由 KBTiller 于 2011-05-18 11:16 編輯

回復(fù) 81# koolcoy


    9^21不需要那么多。位數(shù)為21應(yīng)該可以減去兩支
作者: koolcoy    時(shí)間: 2011-05-18 19:14
用python實(shí)現(xiàn)了一下這個(gè)算法
測試結(jié)果:
[witch@localhost ~]$ for i in 21 23 24; do
> time ./flower.py $i
> done
449177399146038697307
128468643043731391252

real    1m33.091s
user    1m31.283s
sys     0m0.123s
27879694893054074471405
27907865009977052567814
35452590104031691935943
21887696841122916288858
28361281321319229463398

real    2m49.607s
user    2m47.742s
sys     0m0.164s
174088005938065293023722
188451485447897896036875
239313664430041569350093

real    3m40.527s
user    3m38.041s
sys     0m0.160s

  1. #!/usr/bin/env python

  2. import sys

  3. LENGTH = int(sys.argv[1])
  4. TABLE = tuple([tuple([x * (i**LENGTH) for x in range(1, LENGTH + 1)])
  5.                                                 for i in range(1, 10)])
  6. MAX = 10 ** LENGTH - 1
  7. MIN = 10 ** (LENGTH - 1)

  8. def isValidNumber(number, digit):
  9.         tmp = [0] * 10
  10.         for ch in str(number):
  11.                 tmp[ord(ch) - ord('0')] += 1
  12.         tmp.pop(0)
  13.         return tmp == digit

  14. def search(left, index, partialSum, digit):
  15.         if index < 8 and left > 0:
  16.                 search(left, index + 1, partialSum, digit)

  17.         for count in range(1, left + 1):
  18.                 digit[index] = count
  19.                 value = TABLE[index][count - 1]
  20.                 sum = partialSum + value

  21.                 if sum > MAX:
  22.                         break

  23.                 if sum > MIN:
  24.                         if isValidNumber(sum, digit):
  25.                                 print sum
  26.                 if index < 8 and left > count:
  27.                         search(left - count, index + 1, sum, digit)
  28.        
  29.         digit[index] = 0

  30. def main():
  31.         digit = [0] * 9
  32.         search(LENGTH, 0, 0, digit)

  33. if __name__ == "__main__":
  34.         main()
復(fù)制代碼

作者: koolcoy    時(shí)間: 2011-05-18 20:02
[witch@localhost ~]$ time ./flower.py 29
23866716435523975980390369295
14607640612971980372614873089
19008174136254279995012734740
19008174136254279995012734741

real    15m38.757s
user    15m0.449s
sys     0m0.333s
作者: believetruelove    時(shí)間: 2011-05-18 20:41
先mark一下,今天加班太累了。
作者: koolcoy    時(shí)間: 2011-05-18 22:42
又用C++實(shí)現(xiàn)了一下這個(gè)算法,結(jié)果大大地出乎我的意料{:3_189:}

witch:~/Documents/workspace/Flower$ time ./a.out 21
449177399146038697307
128468643043731391252

real        0m9.627s
user        0m9.582s
sys        0m0.008s
witch:~/Documents/workspace/Flower$ time ./a.out 24
174088005938065293023722
188451485447897896036875
239313664430041569350093

real        0m22.139s
user        0m22.119s
sys        0m0.006s

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cstdlib>

  4. template<int LENGTH>
  5. class Integer {
  6.         typedef unsigned int U32;
  7.         typedef unsigned long long U64;
  8. public:
  9.         Integer() {
  10.                 for (int i = 0; i < LENGTH; ++i) {
  11.                         data[i] = 0;
  12.                 }
  13.         }

  14.         Integer(U32 that) {
  15.                 copy(that);
  16.         }

  17.         const Integer& operator = (U32 that) {
  18.                 copy(that);
  19.                 return *this;
  20.         }

  21.         const Integer& operator += (const Integer& that) {
  22.                 int carry = 0;
  23.                 for (int i = 0; i < LENGTH; ++i) {
  24.                         data[i] += that.data[i] + carry;
  25.                         if (data[i] > BASE) {
  26.                                 carry = data[i] / BASE;
  27.                                 data[i] = data[i] % BASE;
  28.                         } else {
  29.                                 carry = 0;
  30.                         }
  31.                 }
  32.                 return *this;
  33.         }

  34.         const Integer& operator *= (U32 that) {
  35.                 U64 carry = 0;
  36.                 for (int i = 0; i < LENGTH; ++i) {
  37.                         U64 tmp = (U64)data[i] * (U64)that + carry;
  38.                         if (tmp > BASE) {
  39.                                 carry = tmp / BASE;
  40.                                 data[i] = tmp % BASE;
  41.                         } else {
  42.                                 carry = 0;
  43.                                 data[i] = tmp;
  44.                         }
  45.                 }
  46.                 return *this;
  47.         }

  48.         Integer operator + (const Integer& that) const {
  49.                 Integer tmp = *this;
  50.                 return tmp += that;
  51.         }

  52.         Integer operator * (U32 that) const {
  53.                 Integer tmp = *this;
  54.                 return tmp *= that;
  55.         }

  56.         bool operator < (const Integer& that) const {
  57.                 for (int i = LENGTH - 1; i >= 0; --i) {
  58.                         if (data[i] < that.data[i]) {
  59.                                 return true;
  60.                         } else if (data[i] > that.data[i]) {
  61.                                 return false;
  62.                         }
  63.                 }
  64.                 return false;
  65.         }

  66.         bool operator > (const Integer& that) const {
  67.                 return std::memcmp(data, that.data, sizeof(data)) != 0
  68.                                 && !(*this < that);
  69.         }

  70.         void validate(char digit[9]) const {
  71.                 char decimal[LENGTH * WIDTH + 1];
  72.                 toString(decimal);

  73.                 char actual[10] = {0};
  74.                 for (int i = 0; i < WIDTH * LENGTH; ++i) {
  75.                         ++actual[decimal[i] - '0'];
  76.                 }
  77.                 if (std::memcmp(actual + 1, digit, 9) == 0) {
  78.                         output(decimal);
  79.                 }
  80.         }

  81.         void toString(char* decimal) const {
  82.                 for (int i = LENGTH - 1; i >= 0; --i) {
  83.                         std::sprintf(decimal + WIDTH * (LENGTH - 1 - i), "%09d", data[i]);
  84.                 }
  85.                 decimal[LENGTH * WIDTH] = 0;
  86.         }

  87.         void show() const {
  88.                 char decimal[LENGTH * WIDTH + 1];
  89.                 toString(decimal);
  90.                 printf("%s\n", decimal);
  91.         }

  92. private:
  93.         enum {
  94.                 BASE = 1000000000, /* This is 10^9 */
  95.                 WIDTH = 9
  96.         };
  97.         U32 data[LENGTH];

  98.         void copy(U32 that) {
  99.                 data[0] = that % BASE;
  100.                 data[1] = that / BASE;
  101.                 for (int i = 2; i < LENGTH; ++i) {
  102.                         data[i] = 0;
  103.                 }
  104.         }

  105.         static void output(const char* decimal) {
  106.                 int i = 0;
  107.                 while (decimal[i] == '0') {
  108.                         ++i;
  109.                 }
  110.                 printf("%s\n", decimal + i);
  111.         }
  112. };

  113. typedef Integer<3> Bigint;

  114. Bigint MIN;
  115. Bigint MAX;
  116. Bigint** TABLE;

  117. void createSumTable(int length) {
  118.         TABLE = new Bigint*[9];
  119.         for (int i = 0; i < 9; ++i) {
  120.                 TABLE[i] = new Bigint[length];

  121.                 TABLE[i][0] = i + 1;
  122.                 for (int j = 1; j < length; ++j) {
  123.                         TABLE[i][0] *= (i + 1);
  124.                 }

  125.                 for (int j = 1; j < length; ++j) {
  126.                         TABLE[i][j] = TABLE[i][0] * (j + 1);
  127.                 }
  128.         }
  129. }

  130. void initialize(int length) {
  131.         MIN = 10;
  132.         for (int i = 0; i < length - 2; ++i) {
  133.                 MIN *= 10;
  134.         }
  135.         MAX = MIN * 10;

  136.         createSumTable(length);
  137. }

  138. void search(int left, int index, Bigint partialSum, char* digit) {
  139.         if (index < 8 && left > 0) {
  140.                 search(left, index + 1, partialSum, digit);
  141.         }
  142.         for (int count = 1; count < left + 1; ++count) {
  143.                 digit[index] = count;
  144.                 Bigint sum = partialSum + TABLE[index][count - 1];

  145.                 if (sum > MAX) {
  146.                         break;
  147.                 }
  148.                 if (sum > MIN) {
  149.                         sum.validate(digit);
  150.                 }
  151.                 if (index < 8 && left > count) {
  152.                         search(left - count, index + 1, sum, digit);
  153.                 }
  154.         }
  155.         digit[index] = 0;
  156. }

  157. int main(int argc, char** argv) {
  158.         int length = 0;
  159.         if (argc != 2 || sscanf(argv[1], "%d", &length) != 1 || length <= 0) {
  160.                 std::fprintf(stderr, "Usage: %s <length>\n", argv[0]);
  161.         }

  162.         initialize(length);
  163.         char* digit = (char*)std::calloc(length, 1);
  164.         search(length, 0, Bigint(0), digit);
  165.         return 0;
  166. }
復(fù)制代碼

作者: koolcoy    時(shí)間: 2011-05-18 22:49
改一行代碼:typedef Integer<4> Bigint
{:3_189:}
witch:~/Documents/workspace/Flower$ time ./a.out 31
1927890457142960697580636236639
2309092682616190307509695338915
1145037275765491025924292050346

real        2m55.434s
user        2m52.737s
sys        0m0.200s
作者: koolcoy    時(shí)間: 2011-05-18 23:55
本帖最后由 koolcoy 于 2011-05-18 23:59 編輯

把sprintf調(diào)用去掉后竟然{:3_182:}{:3_182:}{:3_190:}{:3_190:}

witch:~/Documents/workspace/Flower$ time ./a.out 21
449177399146038697307
128468643043731391252

real        0m2.424s
user        0m2.030s
sys        0m0.003s
witch:~/Documents/workspace/Flower$ time ./a.out 31
1927890457142960697580636236639
2309092682616190307509695338915
1145037275765491025924292050346

real        0m26.691s
user        0m26.639s
sys        0m0.020s

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cstdlib>

  4. template<int LENGTH>
  5. class Integer {
  6.         typedef unsigned int U32;
  7.         typedef unsigned long long U64;
  8. public:
  9.         Integer() {
  10.                 for (int i = 0; i < LENGTH; ++i) {
  11.                         data[i] = 0;
  12.                 }
  13.         }

  14.         Integer(U32 that) {
  15.                 copy(that);
  16.         }

  17.         const Integer& operator = (U32 that) {
  18.                 copy(that);
  19.                 return *this;
  20.         }

  21.         const Integer& operator += (const Integer& that) {
  22.                 int carry = 0;
  23.                 for (int i = 0; i < LENGTH; ++i) {
  24.                         data[i] += that.data[i] + carry;
  25.                         if (data[i] > BASE) {
  26.                                 carry = data[i] / BASE;
  27.                                 data[i] = data[i] % BASE;
  28.                         } else {
  29.                                 carry = 0;
  30.                         }
  31.                 }
  32.                 return *this;
  33.         }

  34.         const Integer& operator *= (U32 that) {
  35.                 U64 carry = 0;
  36.                 for (int i = 0; i < LENGTH; ++i) {
  37.                         U64 tmp = (U64)data[i] * (U64)that + carry;
  38.                         if (tmp > BASE) {
  39.                                 carry = tmp / BASE;
  40.                                 data[i] = tmp % BASE;
  41.                         } else {
  42.                                 carry = 0;
  43.                                 data[i] = tmp;
  44.                         }
  45.                 }
  46.                 return *this;
  47.         }

  48.         Integer operator + (const Integer& that) const {
  49.                 Integer tmp = *this;
  50.                 return tmp += that;
  51.         }

  52.         Integer operator * (U32 that) const {
  53.                 Integer tmp = *this;
  54.                 return tmp *= that;
  55.         }

  56.         bool operator > (const Integer& that) const {
  57.                 for (int i = LENGTH - 1; i >= 0; --i) {
  58.                         if (data[i] > that.data[i]) {
  59.                                 return true;
  60.                         } else if (data[i] < that.data[i]) {
  61.                                 return false;
  62.                         }
  63.                 }
  64.                 return false;
  65.         }

  66.         bool operator < (const Integer& that) const {
  67.                 return std::memcmp(data, that.data, sizeof(data)) != 0
  68.                                 && !(*this > that);
  69.         }

  70.         void validate(char digit[9]) const {
  71.                 char decimal[LENGTH * WIDTH + 1];
  72.                 toString(decimal);

  73.                 char actual[10] = {0};
  74.                 for (int i = 0; i < WIDTH * LENGTH; ++i) {
  75.                         ++actual[decimal[i] - '0'];
  76.                 }
  77.                 if (std::memcmp(actual + 1, digit, 9) == 0) {
  78.                         output(decimal);
  79.                 }
  80.         }

  81.         void toString(char* decimal) const {
  82.                 for (int i = 0; i < LENGTH; ++i) {
  83.                         convertChunk(data[LENGTH - i - 1], decimal + WIDTH * i);
  84.                 }
  85.                 decimal[LENGTH * WIDTH] = 0;
  86.         }

  87. private:
  88.         enum {
  89.                 BASE = 1000000000, /* This is 10^9 */
  90.                 WIDTH = 9
  91.         };
  92.         U32 data[LENGTH];

  93.         static void output(const char* decimal) {
  94.                 int i = 0;
  95.                 while (decimal[i] == '0') {
  96.                         ++i;
  97.                 }
  98.                 printf("%s\n", decimal + i);
  99.         }

  100.         static void convertChunk(U32 digit, char* decimal) {
  101.                 for (int i = 0; i < WIDTH; ++i) {
  102.                         decimal[WIDTH - 1 - i] = digit % 10 + '0';
  103.                         digit /= 10;
  104.                 }
  105.         }

  106.         void copy(U32 that) {
  107.                 data[0] = that % BASE;
  108.                 data[1] = that / BASE;
  109.                 for (int i = 2; i < LENGTH; ++i) {
  110.                         data[i] = 0;
  111.                 }
  112.         }
  113. };

  114. typedef Integer<SIZE> Bigint;

  115. Bigint MIN;
  116. Bigint MAX;
  117. Bigint** TABLE;

  118. void createSumTable(int length) {
  119.         TABLE = new Bigint*[9];
  120.         for (int i = 0; i < 9; ++i) {
  121.                 TABLE[i] = new Bigint[length];

  122.                 TABLE[i][0] = i + 1;
  123.                 for (int j = 1; j < length; ++j) {
  124.                         TABLE[i][0] *= (i + 1);
  125.                 }

  126.                 for (int j = 1; j < length; ++j) {
  127.                         TABLE[i][j] = TABLE[i][0] * (j + 1);
  128.                 }
  129.         }
  130. }

  131. void initialize(int length) {
  132.         MIN = 10;
  133.         for (int i = 0; i < length - 2; ++i) {
  134.                 MIN *= 10;
  135.         }
  136.         MAX = MIN * 10;

  137.         createSumTable(length);
  138. }

  139. void search(int left, int index, Bigint partialSum, char* digit) {
  140.         if (index < 8 && left > 0) {
  141.                 search(left, index + 1, partialSum, digit);
  142.         }
  143.         for (int count = 1; count < left + 1; ++count) {
  144.                 digit[index] = count;
  145.                 Bigint sum = partialSum + TABLE[index][count - 1];

  146.                 if (sum > MAX) {
  147.                         break;
  148.                 }
  149.                 if (sum > MIN) {
  150.                         sum.validate(digit);
  151.                 }
  152.                 if (index < 8 && left > count) {
  153.                         search(left - count, index + 1, sum, digit);
  154.                 }
  155.         }
  156.         digit[index] = 0;
  157. }

  158. int main(int argc, char** argv) {
  159.         int length = 0;
  160.         if (argc != 2 || sscanf(argv[1], "%d", &length) != 1 || length <= 0) {
  161.                 std::fprintf(stderr, "Usage: %s <length>\n", argv[0]);
  162.         }

  163.         initialize(length);
  164.         char* digit = (char*)std::calloc(length, 1);
  165.         search(length, 0, Bigint(0), digit);
  166.         return 0;
  167. }
復(fù)制代碼

作者: KBTiller    時(shí)間: 2011-05-19 09:26
只要是提供組合數(shù)的解法
各種方案的解空間是一樣大的

但是
for(n9 = 1 ; n9 <= 21 ; n9++)
    for(n8 = 0 ; n8 <= 21 - n9 ; n8++)
    ……
方案對所謂的“剪枝”可能更好寫
作者: koolcoy    時(shí)間: 2011-05-19 09:48
回復(fù) 89# KBTiller


    顯然不一樣,按這種方法窮舉的話,其復(fù)雜度是O(N^9),如果按各個(gè)數(shù)位上的數(shù)字來枚舉的話,復(fù)雜度O(9^N),一個(gè)是多項(xiàng)式級的復(fù)雜度,另外一個(gè)是指數(shù)級的復(fù)雜度。復(fù)雜度跟解空間是等價(jià)的。
作者: KBTiller    時(shí)間: 2011-05-19 09:52
本帖最后由 KBTiller 于 2011-05-19 09:57 編輯

回復(fù) 90# koolcoy


    怎么會(huì)呢?21位數(shù)的各種組合的數(shù)目是一定的。這個(gè)值可以精確求出,14139189
    當(dāng)然,我也贊同嵌套的層數(shù)越少越好。但組合的總數(shù)目是一樣的
作者: KBTiller    時(shí)間: 2011-05-19 09:53
回復(fù) 90# koolcoy


    “如果按各個(gè)數(shù)位上的數(shù)字來枚舉的話”,按照10樓得那種枚舉方法,總數(shù)并不多
作者: koolcoy    時(shí)間: 2011-05-19 10:09
兩種算法的組合數(shù)是不一樣的,這兩種算法有著本質(zhì)的區(qū)別。
如果按照“各個(gè)數(shù)位上的數(shù)字來枚舉”的話,即10樓的算法,數(shù)字 123XXXX和321XXXX是兩種不同的情況,需要計(jì)算兩次。
如果按照“1出現(xiàn)的次數(shù)為n1,2出現(xiàn)的次數(shù)n2,3出現(xiàn)的次數(shù)為n3...”這種方法來枚舉的話123XXXX和321XXXX是同一種情況,只需要計(jì)算一次。
作者: KBTiller    時(shí)間: 2011-05-19 10:13
不,10樓的算法提到了“順序符合”,即“有序”,這個(gè)很重要
123XXXX和321XXXX不可能都出現(xiàn)
作者: koolcoy    時(shí)間: 2011-05-19 10:40
回復(fù) 94# KBTiller

但是有個(gè)問題,按照10樓得算法,當(dāng)你驗(yàn)證后發(fā)現(xiàn)123XXXX不滿足條件,怎么知道321XXXX是否滿足條件呢?如果不知道的話,那么你就還要驗(yàn)證321XXXX是否滿足條件。也就是說對于123XXXX和321XXXX這兩個(gè)數(shù)字你需要驗(yàn)證兩次。但是按照我的那種算法,如果發(fā)現(xiàn)123XXXX不滿足條件后,我就可以肯定321XXXX不滿足條件。

ps: 對于21位的數(shù)字,俺已經(jīng)突破1.4秒了{(lán):3_203:}
作者: KBTiller    時(shí)間: 2011-05-19 10:53
回復(fù) 95# koolcoy


    “123XXXX不滿足條件,怎么知道321XXXX是否滿足條件呢?”
   和你那種是一樣的
   用123XXXX計(jì)算出各位數(shù)字N次方的和并統(tǒng)計(jì)各數(shù)字出現(xiàn)的次數(shù)
   然后檢查“各位數(shù)字N次方的和”的各個(gè)數(shù)字出現(xiàn)的次數(shù)與“123XXXX“的“各數(shù)字出現(xiàn)的次數(shù)”是否一致
作者: KBTiller    時(shí)間: 2011-05-19 10:55
回復(fù) 95# koolcoy


   
對于21位的數(shù)字,俺已經(jīng)突破1.4秒了


    可喜可賀!(不過不知道硬件環(huán)境是否一致)
    我后面也準(zhǔn)備改進(jìn)一下,看看能提高多少
作者: koolcoy    時(shí)間: 2011-05-19 11:09
回復(fù) 97# KBTiller

Pentium(R) Dual-Core  CPU  E5700  @ 3.00GHz 32位cygwin
作者: xxw19840406    時(shí)間: 2011-06-15 20:28
128468643043731391252
449177399146038697307




歡迎光臨 Chinaunix (http://www.72891.cn/) Powered by Discuz! X3.2