php九宫格数字(获取九宫格)
华为云服务器特价优惠火热进行中! 2核2G2兆仅需 38 元;4核4G3兆仅需 79 元。购买时间越长越优惠!更多配置及优惠价格请咨询客服。
合作流程: |
今天给各位分享php九宫格数字的知识,其中也会对获取九宫格进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
微信号:cloud7591如需了解更多,欢迎添加客服微信咨询。
复制微信号
本文目录一览:
1到9的九宫格怎么填?
把1到9的数字填入一老轿下九宫格,横竖都不能重复,可以列为以下值:
横竖不重复,每条线上的3个埋含袭数的和都相等。
扩展资料
1-9九宫格数字填写规律口诀 1-9之间一共 9个数,加起来一共45,1+2+3+4+5+6+7+8+9=45。
九宫格是每三个不弯兄同的数字相加是一个相同的一个数字,即45/3=15。
列出8种可能:159;168;249;258;267;348;357;456。
统计,1出现2次,2出现3次,3出现2次,4出现3次,5出现8次,6出现3次,7出现2次,8出现3次,9出现2次。
1、先将1填入第1行最中间一格;
2、沿着右斜向上方向填入下一个数字2;如果右上方的方格不在这个区域内,就将它向水平方向或竖直方向移动(水平方向向左移动到最左端的方格中,竖直方向向下移动到最下面的方格中);
3、如果右上方的方格已经有数字,那么就将下个数字填在前一个数字的下方;
4、如果右上方的方格向左或向右移动都不在区域内,仍然将它填在前一个数字的下方;
5、继续以上步骤,就可以完成所有方格数字的填写。

数字九宫格的解法
分为三种情况:N为奇数、N为4的倍数、N为其它偶数(4n+2的形式)
1、 N为奇数时
⑴ 将1放在第一行中间一列。
⑵ 从2开始直到n×n止各数依次按下列规则存放:按 45°方向行走,如向右下,每一个数存放的行比前一个数的行数减1,列数加1。
⑶ 如果行列范围超出矩阵范围,则回绕。例如1在第1行,则2应放在最上一行,列数同样加1。
⑷ 如果按上面规则确定的位置上已有数,或上一个数是第1行第n列时,则把下一个数放在上一个数的上面。
2、 N为4的倍数时
采用对称元素交换法。首先把数1到n×n按从上至下,从左到右顺序填入矩阵,然后将方阵的所有4×4子方阵中的两对角线上位置的数关于方阵中心作对,称交换,即a(i,j)与a(n+1-i,n+1-j)交换,所有其它位置上的数不变。(或者将对角线不变,其它位置对称交换也可)
3、 N为其它偶数时
当n为非4倍数的偶数(即4n+2形)时:首先把大方阵分解为4个奇数(2m+1阶)子方阵。按上述奇数阶幻方给分解的4个子方阵对应赋值,由小到大依次为上左子阵(i),下右子(i+v),上右子阵(i+2v),下左子阵(i+3v),即4个子方阵对应元素相差v,其中v=n*n/4。
四个子矩阵由小到大排列方式为 ① ③ ④ ②,然后作相应的元素交换:a(i,j)与a(i+u,j)在同一列做对应交换(jt或jn-t+2),a(t-1,0)与a(t+u-1,0);a(t-1,t-1)与困槐a(t+u-1,t-1)两对元素交换。其中u=n/2,t=(n+2)/4 上述交换使行列及对角线上元素之和相等,如下图:
扩展资料
性质:
将n阶幻方看作一个矩阵,记为A,其中的第i行j列的数字记为a(i,j)。在A内两对角线上填写1、2、3、……、n,各行再填写1、2、3、……、n,使各行各列数字之和为n*(n+1)/2。第1行从n到1填写,从第2行到第n/2行按从1到进行填写(第2行第1列填n,第2行第n列填1),从第n/2+1到第n行按n到1进行填写,对角线的方格内数字不变。
n阶幻方是由前n^2(n的2次方)个自然数组成的一个n阶方阵,其各行、各列及两条对角线所含的n个数的和相等。
将从一到若干个数的自然数排成亮消纵横各为若干个数的正方形,使在同一行、同一列和同一对角线上敬尺知的几个数的和都相等。
九宫格拼图·求此问题解法~~思路~代码都可~~就是关于其还原算法的·急~在线等~多谢哈
在一个3×3的九宫中有1-8这8个数及一个空格随机的摆放在其中的格子里,如图1-1所示。现在要求实现这个问题:将其调整为如图1-1右图所示的形式。调整的规则是:每次只能将与空格(上、下、或左、右)相邻的一个数字平移到空格中。试编程实现这一问题的求解。
(图1-1)
二、题目分析:
这是人工智能中的经典难题之一,问题是在3×3方格棋盘中,放8格数,剩下的没有放到的为空,每次移动只能是和相邻的空格交换数。程序自动产生问题的初始状态,通过一系列交换动作将其转换成目标排列(如下图1-2到图1-3的转换)。
(图1-2) (图1-3)
该问题中,程序产生的随机排列转换成目标共有两种可能,而且这两种不可能同时成立,也就是奇数排列和偶数排列。可以把一个随机排列的数组从左到右从上到下用一个一维数组表示,如上图1-2我们就可以表示成{悉庆数8,7,1,5,2,6,3,4,0}其中0代表空格。
在这个数组中我们首先计算它能够重排列出来的结果,公式就是:
∑(F(X))=Y,其中F(X)
是一个数前面比这个数小的数的个数,Y为奇数和偶数时各有一种解法。(八数码问题是否有解的判定 )
上面的数组可以解出它的结果。
F(8)=0;
F(7)=0;
F(1)=0;
F(5)=1;
F(2)=1;
F(6)=3;
F(3)=2;
F(4)=3;
Y=0+0+0+1+1+3+2+3=10
Y=10是偶数,所以其重排列就是如图1-3的结果,如果加起来的结果是奇数重排的结果就是如图1-1最右边的排法。
三、算法分析
求解方法就是交换空格(0)位置,直至到达目标位置为止。图形表示就是:
(图3-1)
要想得到最优的就需要使用广度优先搜索,九宫的所以排列有9!种,也就是362880种排法,数据量是非常大的,使用广度搜索,需要记住每一个结点的排列形式,要是用数组记差埋录的话会占用很多的内存,可以把数据进行适当的压缩。使用DWORD形式保存,压缩形式是每个数字用3位表示,这样就是3×9=27个字节,由于8的二进制表示形式1000,不能用3位表示,使用了一个小技巧就是将8表示为000,然后用多出来的5个字表示8所在的位置,就可以用DWORD表示了。用移位和或操作将数据逐个移入,比乘法速度要快点。睁首定义了几个结果来存储遍历到了结果和搜索完成后保存最优路径。
类结构如下:
class CNineGird
{
public:
struct PlaceList
{
DWORD Place;
PlaceList* Left;
PlaceList* Right;
};
struct Scanbuf
{
DWORD Place;
int ScanID;
};
struct PathList
{
unsigned char Path[9];
};
private:
PlaceList *m_pPlaceList;
Scanbuf *m_pScanbuf;
RECT m_rResetButton;
RECT m_rAutoButton;
public:
int m_iPathsize;
clock_t m_iTime;
UINT m_iStepCount;
unsigned char m_iTargetChess[9];
unsigned char m_iChess[9];
HWND m_hClientWin;
PathList *m_pPathList;
bool m_bAutoRun;
private:
inline bool AddTree(DWORD place , PlaceList* parent);
void FreeTree(PlaceList* parent);
inline void ArrayToDword(unsigned char *array , DWORD data);
inline void DwordToArray(DWORD data , unsigned char *array);
inline bool MoveChess(unsigned char *array , int way);
bool EstimateUncoil(unsigned char *array);
void GetPath(UINT depth);
public:
void MoveChess(int way);
bool ComputeFeel();
void ActiveShaw(HWND hView);
void DrawGird(HDC hDC , RECT clientrect);
void DrawChess(HDC hDC , RECT clientrect);
void Reset();
void OnButton(POINT pnt , HWND hView);
public:
CNineGird();
~CNineGird();
};
计算随机随机数组使用了vector模板用random_shuffle(,)函数来打乱数组数据,并计算目标结果是什么。代码:
void CNineGird::Reset()
{
if(m_bAutoRun) return;
vector vs;
int i;
for (i = 1 ; i 9 ; i ++)
vs.push_back(i);
vs.push_back(0);
random_shuffle(vs.begin(), vs.end());
random_shuffle(vs.begin(), vs.end());
for ( i = 0 ; i 9 ; i ++)
{
m_iChess[i] = vs[i];
}
if (!EstimateUncoil(m_iChess))
{
unsigned char array[9] = {1,2,3,8,0,4,7,6,5};
memcpy(m_iTargetChess , array , 9);
}
else
{
unsigned char array[9] = {1,2,3,4,5,6,7,8,0};
memcpy(m_iTargetChess , array , 9);
}
m_iStepCount = 0;
}
数据压缩函数实现:
inline void CNineGird::ArrayToDword(unsigned char *array , DWORD data)
{
unsigned char night = 0;
for ( int i = 0 ; i 9 ; i ++)
{
if (array[i] == 8)
{
night = (unsigned char)i;
break;
}
}
array[night] = 0;
data = 0;
data = (DWORD)((DWORD)array[0] 29 | (DWORD)array[1] 26 |
(DWORD)array[2] 23 | (DWORD)array[3] 20 |
(DWORD)array[4] 17 | (DWORD)array[5] 14 |
(DWORD)array[6] 11 | (DWORD)array[7] 8 |
(DWORD)array[8] 5 | night);
array[night] = 8;
}
解压缩时跟压缩正好相反,解压代码:
inline void CNineGird::DwordToArray(DWORD data , unsigned char *array)
{
unsigned char chtem;
for ( int i = 0 ; i 9 ; i ++)
{
chtem = (unsigned char)(data (32 - (i + 1) * 3) 0x00000007);
array[i] = chtem;
}
chtem = (unsigned char)(data 0x0000001F);
array[chtem] = 8;
}
由于可扩展的数据量非常的大,加上在保存的时候使用的是DWORD类型,将每一步数据都记录在一个排序二叉树中,按从小到大从左到有的排列,搜索的时候跟每次搜索将近万次的形式比较快几乎是N次方倍,把几个在循环中用到的函数声明为内联函数,并在插入的时候同时搜索插入的数据会不会在树中有重复来加快总体速度。二叉树插入代码:
inline bool CNineGird::AddTree(DWORD place , PlaceList* parent)
{
if (parent == NULL)
{
parent = new PlaceList();
parent-Left = parent-Right = NULL;
parent-Place = place;
return true;
}
if (parent-Place == place)
return false;
if (parent-Place place)
{
return AddTree(place , parent-Right);
}
return AddTree(place , parent-Left);
}
计算结果是奇数排列还是偶数排列的代码:
bool CNineGird::EstimateUncoil(unsigned char *array)
{
int sun = 0;
for ( int i = 0 ; i 8 ; i ++)
{
for ( int j = 0 ; j 9 ; j ++)
{
if (array[j] != 0)
{
if (array[j] == i +1 )
break;
if (array[j] i + 1)
sun++;
}
}
}
if (sun % 2 == 0)
return true;
else
return false;
}
移动到空格位的代码比较简单,只要计算是否会移动到框外面就可以了,并在移动的时候顺便计算一下是不是已经是目标结果,这是用来给用户手工移动是给与提示用的,代码:
inline bool CNineGird::MoveChess(unsigned char *array , int way)
{
int zero , chang;
bool moveok = false;
for ( zero = 0 ; zero 9 ; zero ++)
{
if (array[zero] == 0)
break;
}
POINT pnt;
pnt.x = zero % 3;
pnt.y = int(zero / 3);
switch(way)
{
case 0 : //up
if (pnt.y + 1 3)
{
chang = (pnt.y + 1) * 3 + pnt.x ;
array[zero] = array[chang];
array[chang] = 0;
moveok = true;
}
break;
case 1 : //down
if (pnt.y - 1 -1)
{
chang = (pnt.y - 1) * 3 + pnt.x ;
array[zero] = array[chang];
array[chang] = 0;
moveok = true;
}
break;
case 2 : //left
if (pnt.x + 1 3)
{
chang = pnt.y * 3 + pnt.x + 1;
array[zero] = array[chang];
array[chang] = 0;
moveok = true;
}
break;
case 3 : //right
if (pnt.x - 1 -1)
{
chang = pnt.y * 3 + pnt.x - 1;
array[zero] = array[chang];
array[chang] = 0;
moveok = true;
}
break;
}
if (moveok !m_bAutoRun)
{
m_iStepCount ++ ;
DWORD temp1 ,temp2;
ArrayToDword(array , temp1);
ArrayToDword(m_iTargetChess , temp2);
if (temp1 == temp2)
{
MessageBox(NULL , "你真聪明这么快就搞定了!" , "^_^" , 0);
}
}
return moveok;
}
在进行广度搜索时候,将父结点所在的数组索引记录在子结点中了,所以得到目标排列的时候,只要从子结点逆向搜索就可以得到最优搜索路径了。用变量m_iPathsize来记录总步数,具体函数代码:
void CNineGird::GetPath(UINT depth)
{
int now = 0 , maxpos = 100 ;
UINT parentid;
if (m_pPathList != NULL)
{
delete[] m_pPathList;
}
m_pPathList = new PathList[maxpos];
parentid = m_pScanbuf[depth].ScanID;
DwordToArray(m_pScanbuf[depth].Place , m_pPathList[++now].Path);
while(parentid != -1)
{
if (now == maxpos)
{
maxpos += 10;
PathList * temlist = new PathList[maxpos];
memcpy(temlist , m_pPathList , sizeof(PathList) * (maxpos - 10));
delete[] m_pPathList;
m_pPathList = temlist;
}
DwordToArray(m_pScanbuf[parentid].Place , m_pPathList[++now].Path);
parentid = m_pScanbuf[parentid].ScanID;
}
m_iPathsize = now;
}
动态排列的演示函数最简单了,为了让主窗体有及时刷新的机会,启动了一个线程在需要主窗体刷新的时候,用Slee(UINT)函数来暂停一下线程就可以了。代码:
unsigned __stdcall MoveChessThread(LPVOID pParam)
{
CNineGird * pGird = (CNineGird *)pParam;
RECT rect;
pGird-m_iStepCount = 0;
::GetClientRect(pGird-m_hClientWin , rect);
for ( int i = pGird-m_iPathsize ; i 0 ; i --)
{
memcpy(pGird-m_iChess , pGird-m_pPathList[i].Path , 9);
pGird-m_iStepCount ++;
InvalidateRect( pGird-m_hClientWin , rect , false);
Sleep(300);
}
char msg[100];
sprintf(msg , "^_^ ! 搞定了!\r\n计算步骤用时%d毫秒" , pGird-m_iTime);
MessageBox(NULL , msg , "~_~" , 0);
pGird-m_bAutoRun = false;
return 0L;
}
最后介绍一下搜索函数的原理,首先得到源数组,将其转换成DWORD型,与目标比较,如果相同完成,不同就交换一下数据和空格位置,加入二叉树,搜索下一个结果,直到没有步可走了,在搜索刚刚搜索到的位置的子位置,这样直到找到目标结果为止,函数:
bool CNineGird::ComputeFeel()
{
unsigned char *array = m_iChess;
UINT i;
const int MAXSIZE = 362880;
unsigned char temparray[9];
DWORD target , fountain , parent , parentID = 0 , child = 1;
ArrayToDword(m_iTargetChess , target);
ArrayToDword(array , fountain);
if (fountain == target)
{
return false;
}
if (m_pScanbuf != NULL)
{
delete[] m_pScanbuf;
}
m_pScanbuf = new Scanbuf[MAXSIZE];
AddTree(fountain ,m_pPlaceList);
m_pScanbuf[ 0 ].Place = fountain;
m_pScanbuf[ 0 ].ScanID = -1;
clock_t tim = clock();
while(parentID MAXSIZE child MAXSIZE)
{
parent = m_pScanbuf[parentID].Place;
for ( i = 0 ; i 4 ; i ++) // 0 :UP , 1:Down ,2:Left,3:Right
{
DwordToArray(parent , temparray);
if (MoveChess(temparray,i)) //是否移动成功
{
ArrayToDword(temparray , fountain);
if (AddTree(fountain, m_pPlaceList)) //加入搜索数
{
m_pScanbuf[ child ].Place = fountain;
m_pScanbuf[ child ].ScanID = parentID;
if (fountain == target) //是否找到结果
{
m_iTime = clock() - tim;
GetPath(child);//计算路径
FreeTree(m_pPlaceList);
delete[] m_pScanbuf;
m_pScanbuf = NULL;
return true;
}
child ++;
}
}
} // for i
parentID++;
}
m_iTime = clock() - tim;
FreeTree(m_pPlaceList);
delete[] m_pScanbuf;
m_pScanbuf = NULL;
return false;
}
重要函数的介绍结束;下面是程序的运行结果和运算结果:
关于php九宫格数字和获取九宫格的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。
