为什么要详解?主要是因为我自己看的时候都花了很长时间才明白。
题目:
在9(3 x 3)个方格的方阵中填入数字1到N(N>=10)内的9个数字,使所有相邻两方格内的两个整数之和为质数(素数),试求出所有满足要求的数字填充方案。
先画图:(3*3表格)
|
0 |
1 |
2 |
|
3 |
4 |
5 |
|
6 |
7 |
8 |
由于一维数组更好处理,所以变换成一维数组
a[10]:
|
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
数据结构 1)
int checkM[9][3]={{-1},{0,-1},{1,-1},
{0,-1},{1,3,-1},{2,4,-1},
{3,-1},{4,6,-1},{5,7,-1}};
这是干什么用的呢?
要是相邻方格的数字之和为质数,我们约定试探的时候按照[1…N]的顺序来试探。
这样的话,0号方格不需要和任何单元格匹配,因为他是第一个,所以checkM[0]={-1,0,0};
这说明a[0]不需要任何试探
再看i=1的时候
单元格1和0相邻,所以在单元格1中填入数字的时候要与0号格内的数字之和为质数。
所以checkM[1] = {0,-1,0}; 【注】匹配的时候看到-1就不会继续向下走了。
在看i=4的时候
格4和格1,3,5,7相邻,但是由于我们约定了顺序,只需验证1,3是否合格即可,所以checkM[4]={1,3,-1};
……
上图易于理解:
|
0 |
1 |
2 |
|
3 |
4 |
5 |
|
6 |
7 |
8 |
|
|
0 |
1 |
2 |
|
0 |
-1 |
|
|
|
1 |
0 |
-1 |
|
|
2 |
1 |
-1 |
|
|
3 |
0 |
-1 |
|
|
4 |
1 |
3 |
-1 |
|
5 |
2 |
4 |
-1 |
|
6 |
3 |
-1 |
|
|
7 |
4 |
6 |
-1 |
|
8 |
5 |
7 |
-1 |
数据结构 2)
b[N]
里面装着N个数字[1…N],如果哪个数字被选中拿到矩阵中去,那么就把它从数组b中清除(置零),下次就不会重复选择。如果不用了再置一。
程序段 1)
int selectNum(int start)
{ int j;
for(j=start;j<=N;j++)
if(b[j]!=0) return j;
return 0;
}
从start开始选择以前没有被选过的数字
程序段 2)
int check(int pos)
{ int i;
if(pos<0) return 0;
i=0;
while( checkM[pos][i]!=-1 )
{ if( !isPrime( a[pos]+a[ checkM[pos][i] ] ) ) return 0;
i++;
}
return 1;
}
判断新选择的数字是否符合标准(和为质数)
While循环就是不断的判断a[pos]+a[ checkM[pos][i] ] 是否是质数。这样的好处就是在程序中省去了路径的判断,都则还要在程序中写
if (i-1 >= 0)
{
// try {...}
}
if (i+1 < N)
{
}
if (j-1 >= 0)
{
}
if (j+1 < N)
{
}
来判断4个方向。
程序段 3)
int extend(int pos)
{ a[++pos]=selectNum(1);
b[ a[pos] ] = 0;
return pos;
}
如果当前a[pos]的值满足质数条件,那么该数字放置成功,下面是试探下一个pos。
a[++pos]=selectNum(1); 为下一个路径寻找可行的数字。
b[ a[pos] ] = 0; 将找到数字的可用性置零,即该数已经被引用,不能再选择了。
程序段4)
int change(int pos)
{ int j;
while(pos>=0 && (j=selectNum( a[pos]+1 )) == 0)
b[ a[pos--] ] = 1;
if( pos < 0 ) return -1;
b[ a[pos] ] = 1;
a[pos] = j;
b[j] = 0;
return pos;
}
当一条路走不通,或者该路径的pos==8即该路径已经走完时,选择另一条合适的路径继续试探。
下面是pos == 8 的情况详解:
1. j=selectNum( a[pos]+1 ) ,对于pos==8寻找下一个可行的数字。
2. 如果找不到,即j==0,那么b[ a[pos] ] = 1; 将这个数字退还给b数组,pos--,去试探pos==7是否还有可行的情况。
3. if( pos < 0 ) return -1; 如果都试探过了,那么返回结束。
4. 否则
4.1 将原来a[pos]中的数据退还给数组b
4.2 将a[pos]中的数据置为j(即刚寻到的一个新数据)
4.3 将j在b数组中的位置置零,表示已经被引用
程序段5)
void find()
{ int ok=1, pos=0;
a[pos]=1; b[ a[pos] ]=0;
do
{
if( ok ) {
if( pos == 8 )
{
write(a);
pos = change(pos);
} else {
pos = extend(pos);
}
}
else
pos = change(pos);
ok = check(pos);
//printf("test %d %d %d/n",ok,pos,a[pos]);write(a);(void)getchar();
} while(pos >= 0);
}
这是整体框架
懂了上面的,这个就不难了。
完整代码:
本文详细讲解如何在3x3矩阵中填充1到N的数字,使得相邻两格数字之和为质数。通过一维数组转换、数据结构优化和检查数字选择,实现算法。涉及关键步骤包括:选择未使用数字、检查质数条件、扩展路径以及改变路径。
427

被折叠的 条评论
为什么被折叠?



