1. 程式人生 > >21位大數的水仙花數

21位大數的水仙花數

-------------------------------------------------------------------------

為了簡化說明,以三位數舉例,

因為153、135、315、351、513、531的立方和都是一樣的,均等於 1^3+3^3+5^3 = 153

而我們可以通過逐位檢查 立方和153,發現1出現1次,3出現1次,5出現1次,而0~9中的其他數字均出現0次,出現的次數之和為3,剛好等於153的長度。

由此我們可以得到 利用列舉0~9各個數字出現的次數,得到水仙花數

得到21位水仙花數的具體方法為:

通過10層迴圈,列舉0~9這10個數字出現的次數(每個數字都可能出現0~21次),當所有數字出現次數之和等於21時,說明這時數字的組合有可能為21位水仙花數。進而求出{[(

每個數字的3次方並分別乘以其出現的次數]後的值 之和sum}。例如 當我們列舉到數字6出現了5次,8出現16次 時,由於8+16=21,此時我們計算sum=6^21*5+8^21*16,檢查得到的和sum的各個位,若恰好出現5個6和16個8,說明這種數字組合使得其和為水仙花數

為了減少程式執行時間,我們可以先把0~9的21次方及其不同的出現次數的值利用另外的程式打表,數值儲存到本程式的3維陣列valus[i][j][k],表示數字i的21次方 乘以 j(出現次數)得到的值。需要用到這些值時可直接呼叫,此時我們只需要計算的是10個大數連加,無需計算求冪和乘法,大大節約時間。

valus[i][j][k]陣列內容如下紅色部分:
數字                                                  出現次數
                         0               1            2   。。。。。。。     19           20          21

 0      0^21      0^21*0     0^21*1  0^21*2 。。。。。。。 0^21*19  0^21*20  0^21*21
 1      1^21      1^21*0     1^21*1  1^21*2 。。。。。。。 1^21*19  1^21*20  1^21*21
 2      2^21      2^21*0     2^21*1  2^21*2 。。。。。。。 2^21*19  2^21*20  2^21*21
 3      3^21      3^21*0     3^21*1  3^21*2 。。。。。。。 3^21*19  3^21*20  3^21*21
 4      4^21      4^21*0     4^21*1  4^21*2 。。。。。。。 4^21*19  4^21*20  4^21*21
 5      5^21      5^21*0     5^21*1  5^21*2 。。。。。。。 5^21*19  5^21*20  5^21*21
 6      6^21      6^21*0     6^21*1  6^21*2 。。。。。。。 6^21*19  6^21*20  6^21*21
 7      7^21      7^21*0     7^21*1  7^21*2 。。。。。。。 7^21*19  7^21*20  7^21*21
 8      8^21      8^21*0     8^21*1  8^21*2 。。。。。。。 8^21*19  8^21*20  8^21*21
 9      9^21      9^21*0     9^21*1  9^21*2 。。。。。。。 9^21*19  9^21*20  9^21*21

剪枝:

9^21是一個21位數,9^21*10是一個22位數(超過21),即9^21最多出現9次,因此9只需從0~9次列舉其出現次數,而0不能做數字開頭,0從0~20次列舉,其他數字從0~21次列舉。需要注意的是,在10層的多重列舉迴圈中, CPU切換迴圈層時也需要時間,所以一般來說將次數少的迴圈放在外層,將迴圈次數多的放在內層。故十重迴圈中將9放在最外層,然後是0 、1,然後是剩餘的。

其他位的水仙花也可採用一樣的做法,只需改變valus[i][j][k]儲存的內容 及 數字出現的次數 即可。

#include<iostream>
#include<windows.h>
using namespace std;

//value[i][j][k]為數字i的21次方出現j次的值(即i^21 * j),其中k為該值的長度
char value[10][22][22]={"000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000","000000000000000000000",
                        "000000000000000000000","000000000000000000001","000000000000000000002","000000000000000000003","000000000000000000004","000000000000000000005","000000000000000000006","000000000000000000007","000000000000000000008","000000000000000000009","000000000000000000010","000000000000000000011","000000000000000000012","000000000000000000013","000000000000000000014","000000000000000000015","000000000000000000016","000000000000000000017","000000000000000000018","000000000000000000019","000000000000000000020","000000000000000000021",
                        "000000000000000000000","000000000000002097152","000000000000004194304","000000000000006291456","000000000000008388608","000000000000010485760","000000000000012582912","000000000000014680064","000000000000016777216","000000000000018874368","000000000000020971520","000000000000023068672","000000000000025165824","000000000000027262976","000000000000029360128","000000000000031457280","000000000000033554432","000000000000035651584","000000000000037748736","000000000000039845888","000000000000041943040","000000000000044040192",
                        "000000000000000000000","000000000010460353203","000000000020920706406","000000000031381059609","000000000041841412812","000000000052301766015","000000000062762119218","000000000073222472421","000000000083682825624","000000000094143178827","000000000104603532030","000000000115063885233","000000000125524238436","000000000135984591639","000000000146444944842","000000000156905298045","000000000167365651248","000000000177826004451","000000000188286357654","000000000198746710857","000000000209207064060","000000000219667417263",
                        "000000000000000000000","000000004398046511104","000000008796093022208","000000013194139533312","000000017592186044416","000000021990232555520","000000026388279066624","000000030786325577728","000000035184372088832","000000039582418599936","000000043980465111040","000000048378511622144","000000052776558133248","000000057174604644352","000000061572651155456","000000065970697666560","000000070368744177664","000000074766790688768","000000079164837199872","000000083562883710976","000000087960930222080","000000092358976733184",
                        "000000000000000000000","000000476837158203125","000000953674316406250","000001430511474609375","000001907348632812500","000002384185791015625","000002861022949218750","000003337860107421875","000003814697265625000","000004291534423828125","000004768371582031250","000005245208740234375","000005722045898437500","000006198883056640625","000006675720214843750","000007152557373046875","000007629394531250000","000008106231689453125","000008583068847656250","000009059906005859375","000009536743164062500","000010013580322265625",
                        "000000000000000000000","000021936950640377856","000043873901280755712","000065810851921133568","000087747802561511424","000109684753201889280","000131621703842267136","000153558654482644992","000175495605123022848","000197432555763400704","000219369506403778560","000241306457044156416","000263243407684534272","000285180358324912128","000307117308965289984","000329054259605667840","000350991210246045696","000372928160886423552","000394865111526801408","000416802062167179264","000438739012807557120","000460675963447934976",
                        "000000000000000000000","000558545864083284007","001117091728166568014","001675637592249852021","002234183456333136028","002792729320416420035","003351275184499704042","003909821048582988049","004468366912666272056","005026912776749556063","005585458640832840070","006144004504916124077","006702550368999408084","007261096233082692091","007819642097165976098","008378187961249260105","008936733825332544112","009495279689415828119","010053825553499112126","010612371417582396133","011170917281665680140","011729463145748964147",
                        "000000000000000000000","009223372036854775808","018446744073709551616","027670116110564327424","036893488147419103232","046116860184273879040","055340232221128654848","064563604257983430656","073786976294838206464","083010348331692982272","092233720368547758080","101457092405402533888","110680464442257309696","119903836479112085504","129127208515966861312","138350580552821637120","147573952589676412928","156797324626531188736","166020696663385964544","175244068700240740352","184467440737095516160","193690812773950291968",
                        "000000000000000000000","109418989131512359209","218837978263024718418","328256967394537077627","437675956526049436836","547094945657561796045","656513934789074155254","765932923920586514463","875351913052098873672","984770902183611232881"};

/*10個大數求和*/

void add(char* A0,char* A1,char* A2,char* A3,char* A4,char* A5,char* A6,char* A7,char* A8,char* A9,char* ans)
{
	int a0[22]={0},a1[22]={0},a2[22]={0},a3[22]={0},a4[22]={0},a5[22]={0},a6[22]={0},a7[22]={0},a8[22]={0},a9[22]={0};
	int p=20;

	/*倒序 & 轉換*/

	for(int q=0;q<=20;q++,p--)
	{
		a0[q]=A0[p]-'0';
		a1[q]=A1[p]-'0';
		a2[q]=A2[p]-'0';
		a3[q]=A3[p]-'0';
		a4[q]=A4[p]-'0';
		a5[q]=A5[p]-'0';
		a6[q]=A6[p]-'0';
		a7[q]=A7[p]-'0';
		a8[q]=A8[p]-'0';
		a9[q]=A9[p]-'0';
	}

	int w=0;  //低位到高位的進位
	char* b=new char[22];
	for(p=0;p<=20;p++)
	{
		int temp=a0[p]+a1[p]+a2[p]+a3[p]+a4[p]+a5[p]+a6[p]+a7[p]+a8[p]+a9[p]+w;
		b[p]=temp%10+'0';
		w=temp/10;
	}
	if(w!=0)  //說明ans有22位,不符合
	{
		ans[0]='0';
		ans[1]='\0';
		return;
	}

	for(p=20;w<=20;w++)
		ans[w]=b[p--];  //ans可能不足21位
	ans[w]='\0';
	return;
}

/*判斷ans內各個數字出現的次數 是否與 列舉各個數字時每個數字出現的次數分別相同*/

bool judge(int i0,int i1,int i2,int i3,int i4,int i5,int i6,int i7,int i8,int i9,char* ans)
{
	int time[10]={0};  //ans各個數字出現的次數

	for(int i=0;i<=20;i++)
		time[ ans[i]-'0' ]++;

	if(time[0]==i0 && time[1]==i1 && time[2]==i2 && time[3]==i3 && time[4]==i4 && 
		time[5]==i5 && time[6]==i6 && time[7]==i7 && time[8]==i8 && time[9]==i9)
		return true;

	return false;
}

int main(void)
{
	int time=GetTickCount();
	char ans[22];

	/*列舉數字0~9出現的次數*/

	for(int i9=0;i9<=9;i9++)
	{
		for(int i0=0;i0<=20;i0++)
		{
			if(i0+i9==21)
			{
				add(value[0][i0],value[1][0],value[2][0],value[3][0],value[4][0],value[5][0],value[6][0],value[7][0],value[8][0],value[9][i9],ans);
				if(ans[0]!='0' && judge(i0,0,0,0,0,0,0,0,0,i9,ans))  //ans[0]!='0'保證ans為21位
					cout<<ans<<endl;
				break; //剪枝,此後列舉的 各個數字出現次數之和必定大於21
			}
			for(int i1=0;i1<=21;i1++)
			{
				if(i0+i1+i9==21)
				{
					add(value[0][i0],value[1][i1],value[2][0],value[3][0],value[4][0],value[5][0],value[6][0],value[7][0],value[8][0],value[9][i9],ans);
					if(ans[0]!='0' && judge(i0,i1,0,0,0,0,0,0,0,i9,ans))
						cout<<ans<<endl;
					break;
				}
				for(int i2=0;i2<=21;i2++)
				{
					if(i0+i1+i2+i9==21)
					{
						add(value[0][i0],value[1][i1],value[2][i2],value[3][0],value[4][0],value[5][0],value[6][0],value[7][0],value[8][0],value[9][i9],ans);
						if(ans[0]!='0' && judge(i0,i1,i2,0,0,0,0,0,0,i9,ans))
							cout<<ans<<endl;
						break;
					}
					for(int i3=0;i3<=21;i3++)
					{
						if(i0+i1+i2+i3+i9==21)
						{
							add(value[0][i0],value[1][i1],value[2][i2],value[3][i3],value[4][0],value[5][0],value[6][0],value[7][0],value[8][0],value[9][i9],ans);
							if(ans[0]!='0' && judge(i0,i1,i2,i3,0,0,0,0,0,i9,ans))
								cout<<ans<<endl;
							break;
						}
						for(int i4=0;i4<=21;i4++)
						{
							if(i0+i1+i2+i3+i4+i9==21)
							{
								add(value[0][i0],value[1][i1],value[2][i2],value[3][i3],value[4][i4],value[5][0],value[6][0],value[7][0],value[8][0],value[9][i9],ans);
								if(ans[0]!='0' && judge(i0,i1,i2,i3,i4,0,0,0,0,i9,ans))
									cout<<ans<<endl;
								break;
							}
							for(int i5=0;i5<=21;i5++)
							{
								if(i0+i1+i2+i3+i4+i5+i9==21)
								{
									add(value[0][i0],value[1][i1],value[2][i2],value[3][i3],value[4][i4],value[5][i5],value[6][0],value[7][0],value[8][0],value[9][i9],ans);
									if(ans[0]!='0' && judge(i0,i1,i2,i3,i4,i5,0,0,0,i9,ans))
										cout<<ans<<endl;
									break;
								}
								for(int i6=0;i6<=21;i6++)
								{
									if(i0+i1+i2+i3+i4+i5+i6+i9==21)
									{
										add(value[0][i0],value[1][i1],value[2][i2],value[3][i3],value[4][i4],value[5][i5],value[6][i6],value[7][0],value[8][0],value[9][i9],ans);
										if(ans[0]!='0' && judge(i0,i1,i2,i3,i4,i5,i6,0,0,i9,ans))
											cout<<ans<<endl;
										break;
									}
									for(int i7=0;i7<=21;i7++)
									{
										if(i0+i1+i2+i3+i4+i5+i6+i7+i9==21)
										{
											add(value[0][i0],value[1][i1],value[2][i2],value[3][i3],value[4][i4],value[5][i5],value[6][i6],value[7][i7],value[8][0],value[9][i9],ans);
											if(ans[0]!='0' && judge(i0,i1,i2,i3,i4,i5,i6,i7,0,i9,ans))
												cout<<ans<<endl;
											break;
										}
										for(int i8=0;i8<=21;i8++)
										{
											if(i0+i1+i2+i3+i4+i5+i6+i7+i8+i9==21)
											{
												add(value[0][i0],value[1][i1],value[2][i2],value[3][i3],value[4][i4],value[5][i5],value[6][i6],value[7][i7],value[8][i8],value[9][i9],ans);
												if(ans[0]!='0' && judge(i0,i1,i2,i3,i4,i5,i6,i7,i8,i9,ans))
													cout<<ans<<endl;
												break;
											}
										} //i8
									} //i7
								} //i6
							} //i5
						} //i4
					} //i3
				} //i2
			} //i1
		} //i0
	} //i9
	cout<<"Run Time : "<<GetTickCount()-time<<"ms"<<endl;
	return 0;
}