21位花朵数算法
2013-05-04 10:06
274 查看
/* 128468643043731391252 449177399146038697307*/ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<time.h> /* 128468643043731391252 449177399146038697307*/ //我的程序只用了34秒 //乍一下很难,很容易往那个一位位枚举数字的方向去,但是这样的复杂度很高,尽管加上了一些判断还是于事无补 //我说一下思路吧,先把所有的数字的21次方求出来放在一个数组里保存,然后再去枚举每一个数字有几个, //总共加起来是二十一位数字,这个枚举的操作次数相对刚才的那个是小多了, //然后把这些数的21次方加起来,然后再去判断一下,是不是由这些数字组成就行了 const int BIT=100000000; struct BigNum { int dig[6]; int len; void Clr() { memset(dig,0,sizeof(dig)); len=1; } void Print() { int i; printf("%d",dig[len-1]); for(i=len-2;i>=0;i--) printf("%08d",dig[i]); puts(""); } }; BigNum p[10],MAX,MIN; BigNum sp[10][22]; int take[10]={0}; int LEN=21; int GetLen(BigNum a) { int i; for(i=5;i>0&&a.dig[i]==0;i--); return i+1; } BigNum CarryUp(BigNum a) { int i; for(i=0;i<a.len;i++) { a.dig[i+1]+=a.dig[i]/BIT; a.dig[i]%=BIT; } return a; } BigNum Multi(BigNum a,BigNum b) { BigNum c; int i,j,k; c.Clr(); c.len=a.len+b.len; for(i=0;i<a.len;i++) { for(j=0;j <b.len;j++) { c.dig[i+j]+=a.dig[i]*b.dig[j]; } } c=CarryUp(c); if(c.len>0&&c.dig[c.len-1]==0)c.len--; return c; } BigNum MyPow(BigNum a,int n) { BigNum ret; ret.Clr(); ret.dig[0]++; while(n--) { ret=Multi(ret,a); } return ret; } int Cmp(BigNum a,BigNum b) { if(a.len>b.len)return 1; if(a.len<b.len)return -1; int i; for(i=a.len-1;i>=0&&a.dig[i]==b.dig[i];i--); if(i==-1)return 0; return a.dig[i]-b.dig[i]; } BigNum Add(BigNum a,BigNum b) { int i; if(b.len>a.len)a.len=b.len; for(i=0;i<a.len;i++) { a.dig[i]+=b.dig[i]; } a=CarryUp(a); if(a.dig[a.len])a.len++; return a; } BigNum Deal(BigNum a) { int i; BigNum b; b.Clr(); b.len=3; for(i=7;i>=0;i--) { b.dig[0]=b.dig[0]*10+a.dig[i]; } for(i=15;i>=8;i--) { b.dig[1]=b.dig[1]*10+a.dig[i]; } for(i=23;i>=16;i--) { b.dig[2]=b.dig[2]*10+a.dig[i]; } return b; } bool ok(BigNum sum) { int aa[10]={0}; int i; for(i=0;i<8;i++) { aa[sum.dig[0]%10]++; aa[sum.dig[1]%10]++; sum.dig[0]/=10; sum.dig[1]/=10; } for(i=0;i<5;i++) { aa[sum.dig[2]%10]++; sum.dig[2]/=10; } for(i=0;i<10&&aa[i]==take[i];i++); return i==10; } void DFS(int deep,BigNum Sum,int leave) { BigNum check; BigNum cc; int i; if(deep==10) { if(leave>0)return; if(ok(Sum)) { Sum.Print(); } return ; } for(i=0;i<=leave;i++) { take[deep]=i; check=Add(Sum,sp[deep][i]); if(Cmp(check,MAX)>=0)break; cc=Add(check,sp[9][leave-i]); if(Cmp(cc,MIN)<0)continue; DFS(deep+1,check,leave-i); } } int main() { int i; int j; BigNum tmp; BigNum sum; tmp.Clr(); int start=time(NULL),finish; for(i=0;i<10;i++) { p[i]=MyPow(tmp,LEN); tmp.dig[0]++; } for(i=0;i<10;i++)sp[i][0].Clr(); for(j=0;j<10;j++) for(i=1;i<22;i++) { sp[j][i]=Add(sp[j][i-1],p[j]); } tmp.Clr(); tmp.len=LEN; sum.Clr(); MAX.dig[2]=100000; MAX.len=3; MIN.dig[2]=10000; MIN.len=3; DFS(0,sum,LEN); finish = time(NULL); printf("%d\n",(finish-start)); return 0; }