- 注册时间
- 2009-2-12
- 最后登录
- 1970-1-1
- 威望
- 星
- 金币
- 枚
- 贡献
- 分
- 经验
- 点
- 鲜花
- 朵
- 魅力
- 点
- 上传
- 次
- 下载
- 次
- 积分
- 22697
- 在线时间
- 小时
|
发表于 2017-9-28 16:22:41
|
显示全部楼层
我把我的代码贴出来,用到了 C++ + cln(https://www.ginac.de/CLN/)
圆上的格子用线性队列存储。元素个数以$8/3$的倍率指数递增,所以此处是性能瓶颈(内存和cpu),时空的复杂度均为 $O((8/3)^n),n $为迭代次数。
- #include <iostream>
- #include <queue>
- #include <cln/rational_io.h>
- using namespace std;
- typedef cln::cl_RA T;
- //typedef unsigned long long T;
- typedef struct counter{T half;T one;} counter;
- typedef struct Point2d{cln::cl_RA x;cln::cl_RA y;} Point2d;
- typedef struct Context {
- counter outer;
- std::queue<Point2d> on;
- counter inner;
- cln::cl_RA sideLen;
- } Context;
- void walkMengerCircle(Context &c){
- static int kernel[8][2] = {{-1, -1},{-1, 0},{-1, 1},{0, -1},{0, 1},{1, -1},{1, 0},{1, 1}};
- cln::cl_RA newslength = c.sideLen/3;
- c.sideLen = newslength;
- ///////////////////////////
- counter out;
- out.half = c.outer.half*2;
- out.one = c.outer.one*8 + c.outer.half*3;
- ///////////////////////////
- counter in;
- in.half = out.half*3-1;
- in.one = c.inner.one*8 + c.inner.half*3;
- ///////////////////////////
- for(size_t j=0,s = c.on.size();j<s;++j){
- Point2d v = c.on.front();
- c.on.pop();
- for(size_t i=0;i<8;++i){
- Point2d center = {v.x+ kernel[i][0]*newslength,v.y+ kernel[i][1]*newslength};
- Point2d lower = {center.x - newslength/2,center.y - newslength/2};
- Point2d upper = {center.x + newslength/2,center.y + newslength/2};
- cl_signean s1 = cln::compare("1/4",lower.x*lower.x + lower.y*lower.y);
- cl_signean s2 = cln::compare("1/4",upper.x*upper.x + upper.y*upper.y);
- //assuming that s2<s1 is always valid.
- if(s2<0&&s1>0){
- c.on.push(center);
- } else if(s1<0){
- out.one ++;
- } else {
- in.one ++;
- }
- }
- }
- ///////////////////////////
- c.on.push({"1/2"-newslength/2,newslength});
- in.one +=2;
- ///////////////////////////
- c.inner = in;
- c.outer = out;
- }
- int main()
- {
- /*
- {{{0, 8, 0}, 8},
- {{4, 28, 32}, 64},
- {{104, 76, 332}, 512},
- {{984, 204, 2908}, 4096},
- {{8288, 580, 23900}, 32768},
- {{67744, 1556, 192844}, 262144},
- {{545904, 4180, 1547068}, 2097152},
- {{4377944, 11204, 12388068}, 16777216},
- {{35052688, 29724, 99135316}, 134217728},
- {{280499768, 79276, 793162780}, 1073741824},
- {{2244206376, 212076, 6345516140}, 8589934592},
- {{17954209288, 565692, 50764701756}, 68719476736},
- {{143635171632, 1509332, 406119132924}, 549755813888},
- {{1149085383304, 4026028, 3248957101772}, 4398046511104},
- {{9192693786392, 10740796, 25991667561644}, 35184372088832},
- {{73541578891856, 28646804, 207933369171996}, 281474976710656},
- {{588332707461496, 76396620, 1663467029827132}, 2251799813685248},
- {{4706661863240488, 203728972, 13307736442512524}, 18014398509481984},
- {{37653295449008288, 543283204, 106461892083564380}, 144115188075855872},
- {{301226365040331144, 1448779164, 851695138117736668}, 1152921504606846976}}
- */
- // {{1,0},{{"4/9", "1/9"}, {"4/9", "2/9"}, {"4/9", "1/3"}},{2,3},"1/9"}
- // {{2^(n-2),*},******************************************,{3*2^(n-2)-1,*},"1/3^n"}
- Context context;
- context.outer = {1,0};
- context.on.push({"4/9", "1/9"});
- context.on.push({"4/9", "2/9"});
- context.on.push({"4/9", "3/9"});
- context.inner = {2,3};
- context.sideLen = "1/9";
- for(int depth=3;depth<=15;++depth){
- walkMengerCircle(context);
- cout <<depth<<":{"<<8*context.outer.one+4*context.outer.half<<","
- <<8*context.on.size()+4<<","
- << 8*context.inner.one+ 4*context.inner.half<<"},"<<context.sideLen;
- // cout <<depth<<":{"<<context.outer.half<<","<<context.outer.one<<"},"
- // <<context.on.size()<<",{"
- // <<context.inner.half<<","<<context.inner.one<<"},"<<context.sideLen;
- cout <<endl;
- }
- return 0;
- }
复制代码
征得KeyTo9_Fans的同意后,也把他的代码贴出来:
- #include<cstdio>
- int i,l=20;
- unsigned __int64 ou[96],in[96],s,r;
- void f(unsigned __int64 a,unsigned __int64 b,unsigned __int64 c,unsigned __int64 d,unsigned __int64 r,int h)
- {
- if(b*b+d*d<=r)in[h]+=2;
- else
- if(a*a+c*c>=r)ou[h]+=2;
- else
- if(h++<l)
- r*=9,
- f(a+a+a,a+a+b,c+c+c,c+c+d,r,h),
- f(a+a+b,a+b+b,c+c+c,c+c+d,r,h),
- f(a+b+b,b+b+b,c+c+c,c+c+d,r,h),
- f(a+a+a,a+a+b,c+c+d,c+d+d,r,h),
- f(a+b+b,b+b+b,c+c+d,c+d+d,r,h),
- f(a+a+a,a+a+b,c+d+d,d+d+d,r,h),
- f(a+a+b,a+b+b,c+d+d,d+d+d,r,h),
- f(a+b+b,b+b+b,c+d+d,d+d+d,r,h);
- }
- int main()
- {
- ou[2]=1,in[2]=3;
- f(3,5,7,9,81,2),f(5,7,7,9,81,2);
- for(r=9,s=16,i=2;i<=l;i++,s<<=3,r*=3)
- {
- in[i]+=5;
- f(1,3,r-2,r,r*r,i);
- if(i>2)in[i]+=in[i-1]<<3,ou[i]+=ou[i-1]<<3;
- printf("{%I64u,%I64u,%I64u},%I64u,{%.16lf,%.16lf,%.16lf}\n",ou[i]<<2,s-in[i]-ou[i]<<2,in[i]<<2,s<<2,1.0*ou[i]/s,1.0*(s-in[i]-ou[i])/s,1.0*in[i]/s);
- }
- return 0;
- }
复制代码
他只取$1/8$的圆,直接计算第$2$层到第$l$层内外部的完整正方形个数,没有保存中间结果,全程采用$64bit$的整数运算,时间复杂度为$O((8/3)^n)$,空间复杂度为$O(n)$。
将上述代码稍作修改,进行更多层迭代:
- #include<cstdio>
- int i,l=32;
- unsigned __int64 ou[96],in[96],s,r,z=1ULL<<63;
- void f(unsigned __int64 a,unsigned __int64 b,unsigned __int64 c,unsigned __int64 d,unsigned __int64 r,int h)
- {
- if(r-b*b-d*d<z)in[h]+=2;
- else
- if(a*a+c*c-r<z)ou[h]+=2;
- else
- if(h++<l)
- r*=9,
- f(a+a+a,a+a+b,c+c+c,c+c+d,r,h),
- f(a+a+b,a+b+b,c+c+c,c+c+d,r,h),
- f(a+b+b,b+b+b,c+c+c,c+c+d,r,h),
- f(a+a+a,a+a+b,c+c+d,c+d+d,r,h),
- f(a+b+b,b+b+b,c+c+d,c+d+d,r,h),
- f(a+a+a,a+a+b,c+d+d,d+d+d,r,h),
- f(a+a+b,a+b+b,c+d+d,d+d+d,r,h),
- f(a+b+b,b+b+b,c+d+d,d+d+d,r,h);
- }
- int main()
- {
- ou[2]=1,in[2]=3;
- f(3,5,7,9,81,2),puts("*"),f(5,7,7,9,81,2),puts("**");
- for(r=9,s=16,i=2;i<=l;i++,s<<=3,r*=3)
- {
- in[i]+=5;
- f(1,3,r-2,r,r*r,i);
- printf("%I64u %I64u\n",in[i],ou[i]);
- }
- return 0;
- }
复制代码
虽然坐标的平方和会超出$64bit$整数范围,但是与圆半径的平方进行比较的时候,两者的差异不会超过$2^63$,因此只看平方运算结果的最后$64bit$足矣
于是跑32层迭代也是妥妥的,根本无需进行更高精度的运算,只是需要18天罢了。 |
|