六角幻方(高斯消元法求解)

编程入门 行业动态 更新时间:2024-10-07 00:27:26

六角幻方(<a href=https://www.elefans.com/category/jswz/34/1768456.html style=高斯消元法求解)"/>

六角幻方(高斯消元法求解)

看了网上很多都是用dfs解决的,于是自己就写了一篇用高斯消元法的解决方法

问题描述

把 1 2 3 … 19 共19个整数排列成六角形状,如下:

要求每个直线上的数字之和必须相等。共有15条直线哦!

再给点线索吧!我们预先填好了2个数字,第一行的头两个数字是:15 13,参见下图,黄色一行为所求。

请你填写出中间一行的5个数字。数字间用空格分开。

这是一行用空格分开的整数,请通过浏览器提交答案,不要填写任何多余的内容(比如说明性的文字等)

解法

把15条直线看成是15条方程,每一个圆看成一个未知数,且未知数的系数为1即六角幻方对应的未知数:

	 x0  x1  x2 x3  x4  x5  x6 x7  x8  x9  x10  x11x12  x13  x14  x15x16  x17  x18 

x0+x1+x2=38
x3+x4+x5+x6=38
x7+x8+x9+x10+x11=38
x12+x13+x14+x15=38
x16+x17+x18=38
…太多了,我就不写了

代码

/*六角幻方的各个数的下标 x0  x1  x2 x3  x4  x5  x6 x7  x8  x9  x10  x11x12  x13  x14  x15x16  x17  x18 
*/ #include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
#define N 19
#define M 15
int am[M][N],bm[M],col[N],vi[N],ans[N],ans2[N];
int in[M][7]={ 
{0,1,2,-1},	 //-1作为结尾标志
{3,4,5,6,-1},
{7,8,9,10,11,-1},
{12,13,14,15,-1},
{16,17,18,-1},
{0,3,7,-1},
{1,4,8,12,-1},
{2,5,9,13,16,-1},
{6,10,14,17,-1},
{11,15,18,-1},
{2,6,11,-1},
{1,5,10,15,-1},
{0,4,9,14,18,-1},
{3,8,13,17,-1},
{7,12,16,-1}
};
void init(){memset(am,0,sizeof(am));for(int i=0;i<M;i++){for(int j=0;in[i][j]!=-1;j++){am[i][in[i][j]]=1;}bm[i]=38;/*由于1到19的累加和为109,通过对图中随便构成5条不相交的直线,即  {0,1,2,-1},{3,4,5,6,-1},{7,8,9,10,11,-1},{12,13,14,15,-1},{16,17,18,-1},作为5条直线,且由题意可知每条直线总和相等,所以109/5=38,即每条直线必定和为38*/ } for(int i=0;i<N;i++)col[i]=i;//因为高斯消元中有交换列的处理,所以要标志i列为那个未知数 
}
void r_swap(int i,int j){if(i==j) return ;for(int k=0;k<N;k++){swap(am[i][k],am[j][k]);}swap(bm[i],bm[j]);
}
void c_swap(int k){int i;for(i=k;i<N;i++){if(am[k][i]!=0)break;}if(k==i || i>=N) return ;for(int j=0;j<M;j++){swap(am[j][k],am[j][i]);}swap(col[k],col[i]);
}
int gcd(int a,int b){return b==0?a:gcd(b,a%b);
}
void xiao_yuan(int k,int j){int u=am[k][k],v=am[j][k];if(u==0||v==0) return ;int g=gcd(u,v);for(int i=0;i<N;i++)//必须从0开始,因为这一行要乘以u/g,且从0开始的元素并不一定为0 {am[j][i]=(u*am[j][i]-v*am[k][i])/g;/*原本为am[j][i]=am[j][i]-v/u*am[k][i]);但是v/u可能存在精度误差,所以解决这个问题最好是在计算过程中得出的都是整数将 am[j][i]=am[j][i]-v/u*am[k][i])两边乘以u,得 u*am[j][i]=u*am[j][i]-v*am[k][i]由于将方程组中的某一行两边同时乘以一个数,并不会影响方程组的求解,所以可以令am[j][i]=u*am[j][i]=u*am[j][i]-v*am[k][i],即 am[j][i]=u*am[j][i]-v*am[k][i]由于 u*am[j][i]-v*am[k][i]可能结果很大,所以除以u和v的最大公约数最终得到 am[j][i]=(u*am[j][i]-v*am[k][i])/g的形式 */ }bm[j]=(u*bm[j]-v*bm[k])/g;//此处跟 am[j][i]=(u*am[j][i]-v*am[k][i])/g同理 
}
void show(){/*static int cnt=0;printf("第%d次消元\n",cnt);*/printf("最终消元结果:\n");for(int i=0;i<N;i++){printf("%5d",col[i]);}printf("   bm\n");for(int i=0;i<(N+1)*5;i++)printf("%c",'-');printf("\n");for(int i=0;i<M;i++){for(int j=0;j<N;j++)printf("%5d",am[i][j]);printf("%5d\n",bm[i]);}printf("\n\n");
}
void guass(){for(int i=0;i<M;i++){//show();for(int j=i;j<M;j++){if(am[j][i]!=0){r_swap(i,j);//找到不为零的行就交换 break;}}c_swap(i);//如果没有找到不为零的行,就找不为零的列,然后交换 for(int j=0;j<M;j++){if(j!=i)xiao_yuan(i,j);}			}
}
void output(){//static int cnt=1;//printf("no.%d\n",cnt++); if(ans2[0]!=15||ans2[1]!=13)//不满足题目要求的结果不显示 return ;printf("%*c%2d  %2d  %2d%*c\n\n",4,' ',ans2[0],ans2[1],ans2[2],6,' ');printf("%*c%2d  %2d  %2d  %2d%*c\n\n",2,' ',ans2[3],ans2[4],ans2[5],ans2[6],3,' ');printf("%2d  %2d  %2d  %2d  %2d\n\n",ans2[7],ans2[8],ans2[9],ans2[10],ans2[11]);printf("%*c%2d  %2d  %2d  %2d%*c\n\n",2,' ',ans2[12],ans2[13],ans2[14],ans2[15],3,' ');printf("%*c%2d  %2d  %2d%*c\n\n\n",4,' ',ans2[16],ans2[17],ans2[18],6,' ');//getchar();
}
void check(){for(int i=11;i>=0;i--){int t=0;for(int j=12;j<N;j++){t+=am[i][j]*ans[j];}t=(bm[i]-t)/am[i][i];if(t<1||t>N)return ;for(int j=i+1;j<N;j++){/*判断填进去的数字是否有重复,此处其实可以使用set树,然后查找,即时间复杂度为log2(N),但是这里N=19,运算量不大,所以不使用该方法,有兴趣的小伙伴可以自己做一做 */ if(t==ans[j])return ;			}ans[i]=t;}for(int i=0;i<N;i++){ans2[col[i]]=ans[i];//将结果放回第i列对应的未知数内 }output();
}
void f(int *ans,int k){if(k<12)//由于最后求出的行最简形矩阵只有12行,所以另外7未知数要事先填进去 {check();return ;}for(int i=1;i<=N;i++){bool flag=true;for(int j=k+1;j<N;j++){if(i==ans[j]){flag=false;break;}}if(flag){ans[k]=i; f(ans,k-1);}}
}
int main(){init();guass();show();f(ans,18);return 0;
}

结果

更多推荐

六角幻方(高斯消元法求解)

本文发布于:2024-02-13 17:46:50,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1760117.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:高斯   幻方   消元法

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!