正三十边形的对角线可将其为多少部分

博客探讨了正三十边形的对角线如何将其分割成多个区域的问题,经过计算得出共有21480个区域。

From http://218.1.231.240/iqbbs/dispbbs.asp?boardid=16&id=152836

最后计算出来是21480个区域。

 

 

 

首先计算交点数目:计算结果为16801个交点

假设Z=exp(Pi/15*i)=cos(Pi/15)+i*sin(Pi/15)

那么Z^15=-1, Z^30=1.点1,Z,Z^2,...,Z^29在复平面上构成正30边形。

而Z的极小多项式是1+Z-Z^3-Z^4-Z^5+Z^7+Z^8。

也就是上面表达是关于Z是0,而任意次数低于8的有理系数多项式,不可能在Z这点取0。(不包括0多项式)

这个多边形所有顶点都是Q[Z]中的点(也就是所有有理系数多项式将Z代入后可能的取值),所以它们对角线的交点

也会在Q[Z]中。现在我的算法就是将每个对角线的交点用关于Z的次数低于8的有理多项式表示出来,这种表示方法必然是唯一的。如果两个交点它们的多项式相同,那么就是同一个点,不然不同。

 
 

第一个程序,计算所有的交点,并输出,输出格式是每行都是

 

a,b,c,d,e,f,g,h[i,j,s,t]

 

其中前面8个数表示这个交点是
a+bZ+cZ^2+dZ^3+eZ^4+fZ^5+gZ^6+hZ^7

 

后面四个数表示这个点是直线Z^i Z^j 和 直线Z^s Z^t的交点。

 

#include <stdio.h>
#include <process.h>
__int64 factor(__int64 a,__int64 b){
if(b==0)return a;
else return factor(b,a%b);
}

 

class Q{
__int64 _up;
__int64 _down;
void Normalize(){
__int64 fac=factor(_up,_down);
_down/=fac;
_up/=fac;
if(_down<0){
_down=-_down;
_up=-_up;
}
}
public:
Q():_up(0),_down(1){}
Q(__int64 up,__int64 down):_up(up),_down(down){}
Q(__int64 x):_up(x),_down(1){}
Q& operator+=(const Q& x);
Q& operator-=(const Q& x);
Q& operator*=(const Q& x);
Q& operator/=(const Q& x);
Q operator-()const{Q tmp=*this;tmp._up=-_up;return tmp;}
Q operator+(const Q& x)const{Q tmp=*this;tmp+=x;return tmp;}
Q operator-(const Q& x)const{Q tmp=*this;tmp-=x;return tmp;}
Q operator*(const Q& x)const{Q tmp=*this;tmp*=x;return tmp;}
Q operator/(const Q& x)const{Q tmp=*this;tmp/=x;return tmp;}
bool iszero()const{return _up==0;}
bool operator==(const Q& x)const{return _up==x._up&&_down==x._down;}
void output()const{if(_down==1)printf("% 4I64d",_up);else printf("% 2I64d/%I64d",_up,_down);}
};

 

Q& Q::operator +=(const Q& x){
_up=_up*x._down+_down*x._up;
_down*=x._down;
Normalize();
return *this;
}

 

Q& Q::operator -=(const Q& x){
_up=_up*x._down-_down*x._up;
_down*=x._down;
Normalize();
return *this;
}

 

Q& Q::operator *=(const Q& x){
_up*=x._up;
_down*=x._down;
Normalize();
return *this;
}

 

Q& Q::operator /=(const Q& x){
_up*=x._down;
_down*=x._up;
Normalize();
return *this;
}

 

Q mod[9]={Q(1),Q(1),Q(0),Q(-1),Q(-1),Q(-1),Q(0),Q(1),Q(1)};

 

void Mod(Q a[15]){
int i,j;
for(i=14;i>=8;i--){
Q divider=a[ i ];
for(j=0;j<=8;j++){
a[i-j]-=divider*mod[8-j];
}
}
}

 

void Dump(const Q M[15][15], const Q b[15]){
int i,j;
printf("//n//n");
for(i=0;i<15;i++){
for(j=0;j<14;j++){
M[j][ i ].output();
printf(",");
}
M[j][ i ].output();
printf("=");
b[ i ].output();
printf("//n");
}
}

 

void SolveEquation(Q M[8][8],Q b[15]){
int i,j,k;
for(i=0;i<8;i++){
// Dump(M,b);
for(j=i;j<8;j++)
if(!M[ i ][j].iszero())break;
if(j!=i){
if(j>=8){
printf("There/'s no inverse for the matrix//n");
exit(-1);
}
for(k=0;k<8;k++){
Q tmp=M[k][ i ];
M[k][ i ]=M[k][j];
M[k][j]=tmp;
}
Q tmp=b[ i ];
b[ i ]=b[j];
b[j]=tmp;
}
Q divider=M[ i ][ i ];
for(j=i;j<8;j++)M[j][ i ]/=divider;
b[ i ]/=divider;
for(j=0;j<8;j++){
if(j==i)continue;
Q mult=M[ i ][j];
for(k=i;k<8;k++)M[k][j]-=mult*M[k][ i ];
b[j]-=mult*b[ i ];
}
}
}

 

void Inverse(const Q a[15], Q b[15]){
Q M[8][8];
Q tmp[15];
int i,j;
for(i=0;i<8;i++){
for(j=0;j<15;j++)tmp[j]=Q(0);
for(j=0;j<8;j++)tmp[i+j]=a[j];
Mod(tmp);
for(j=0;j<8;j++){
M[ i ][j]=tmp[j];
}
}
b[0]=Q(1);
for(i=1;i<15;i++)b[ i ]=Q(0);
SolveEquation(M,b);
}

 

void Multiple(const Q a[15], const Q b[15], Q c[15]){
int i,j;
for(i=0;i<15;i++)c=Q(0);
for(i=0;i<15;i++)for(j=0;j<15;j++){
if(i+j<15){
c[i+j]+=a[ i ]*b[ j ];
}else{
c[i+j-15]-=a[ i ]*b[ j ];
}
}
Mod(c);
}

 

void Output(const Q r[15],int i,int j,int s,int k){
int u;
for(u=0;u<7;u++){
r[u].output();
printf(",");
}
r[u].output();
printf("[%d,%d,%d,%d]//n",i,j,s,k);
}

 

#define INC(z, x) do{//
int tmp=(x)%30;if(tmp<0)tmp+=30;//
if(tmp<15)(z)[tmp]+=Q(1);//
else (z)[tmp-15]-=Q(1);//
}while(0)

 

#define DEC(z, x) do{//
int tmp=(x)%30;if(tmp<0)tmp+=30;//
if(tmp<15)(z)[tmp]-=Q(1);//
else (z)[tmp-15]+=Q(1);//
}while(0)

 

void Find(int i,int j,int s,int t){
int k;
// printf("%d %d %d %d//n",i,j,s,t);
Q delta[15],invdelta[15],r[15];
for(k=0;k<15;k++){
delta[k]=0;
}
INC(delta,j-t);DEC(delta,i-t);DEC(delta,j-s);INC(delta,i-s);
DEC(delta,t-j);INC(delta,t-i);INC(delta,s-j);DEC(delta,s-i);
Mod(delta);
Inverse(delta,invdelta);
for(k=0;k<15;k++)delta[k]=0;
INC(delta,i-j+s);DEC(delta,i-j+t);DEC(delta,-i+j+s);INC(delta,-i+j+t);
INC(delta,j+s-t);DEC(delta,i+s-t);DEC(delta,j-s+t);INC(delta,i-s+t);
Mod(delta);
Multiple(invdelta,delta,r);
Output(r,i,j,s,t);
}

 

int main(){
int i,j,s,t;
for(i=0;i<30;i++)for(s=i+1;s<30;s++)for(j=s+1;j<30;j++)for(t=j+1;t<30;t++){
Find(i,j,s,t);
}
}


上面的程序可以给出每条对角线上经过那些交点,每个交点有多少对角线经过,有了这个信息,接下去很简单。

上面程序还不能直接算出交点数目,需要对输出结果线排序(用sort命令就可以了),然后通过计算机处理出去冗余的点,就可以数出结果了。

 

最后计算出来是21480个区域。
计算公式是Sum{(d(i)-1), d(i)是第i个交点经过的对角线数目}+1+L, L是对角线的数目。
这里c30.sort.txt是上面的程序的输出结果排序后的结果。

 

#include <stdio.h>
#include <string.h>
#define MAXSIZE 100
struct Intersect{
int i,j,s,t;
}Backup[MAXSIZE];
struct Points{
int x,y;
}Tmp[MAXSIZE];
int DumpPoints(FILE *out, char *result,int lcount)
{
int c,i,j;
fprintf(out,"%s[",result);
for(i=0,c=0;i<lcount;i++){
int x,y;
x=Backup[ i ].i;y=Backup[ i].j;
for(j=0;j<c;j++){
if(Tmp[j].x==x&&Tmp[j].y==y)break;
}
if(j==c){
Tmp[j].x=x;Tmp[j].y=y;
c++;
}
x=Backup[ i ].s;y=Backup[ i ].t;
for(j=0;j<c;j++){
if(Tmp[j].x==x&&Tmp[j].y==y)break;
}
if(j==c){
Tmp[j].x=x;Tmp[j].y=y;
c++;
}
}
for(i=0;i<c;i++){
fprintf(out,"(%d,%d)",Tmp[ i ].x,Tmp[ i ].y);
}
fprintf(out,"]//n");
return c;
}

 

 

 

int main()
{
char buf[100];
char prev[100]="";
char *p, *q;int lcount=0,scount=0;
int i,j,s,t,sum;
FILE *in=fopen("c30.sort.txt","r");
FILE *out=fopen("c30.dup.txt","w");
q=prev;sum=0;
while(!feof(in)){
fgets(buf,100,in);
p=strchr(buf,/'[/');
if(p==NULL)continue;
*p=/'//0/';p++;
if(strcmp(buf,prev)){//Start new string
int c=DumpPoints(out,prev,lcount);
if(c>0)sum+=c-1;
lcount=0;
strcpy(prev,buf);
q=prev+(p-buf);
strcpy(q,p);
scount=0;
}
sscanf(p,"%d,%d,%d,%d",&i,&j,&s,&t);
if(lcount<MAXSIZE){
Backup[lcount].i=i;Backup[lcount].j=j;Backup[lcount].s=s;Backup[lcount].t=t;
}
if(j-i!=15&&t-s!=15){
scount++;
}
lcount++;
}
sum+=DumpPoints(out,prev,lcount)-1;
fclose(in);
fclose(out);
printf("Total %d//n",sum+15*27+1);
}

 

 

 参考文章

--  作者:duz
--  发布时间:2005-3-11 9:37:41
--  
关于本题的一个pdf文件 :http://math.berkeley.edu/~poonen/papers/ngon.pdf
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值