数字移动
在图中的九个点上,空出中间的点,其余的点上任意填入数字1到8;1的位置固定不动,然后移动其余的数字,使1到8顺时针从小到大排列.移动的规律是:只能将数字沿线移向空白的点.
请编程显示数字移动过程。
*问题分析与算法设计
分析题目中的条件,要求利用中间的空白格将数字顺时针方向排列,且排列过程中只能借空白的点来移动数字.问题的实质就是将矩阵外面的8个格看成一个环,8个数字在环内进行排序,同于受题目要求的限制"只能将数字沿线移向空白的点",所以要利用中间的空格进行排序,这样要求的排序算法与众不同.
观察中间的点,它是唯一一个与其它8个点有连线的点,即它是中心点.中心点的活动的空间最大,它可以向8个方向移动,充分利用中心点这个特性是算法设计成功与否的关键.
在找到1所在的位置后,其余各个数字的正确位置就是固定的.我们可以按照下列算法从数字2开始,一个一个地来调整各个数字的位置.
*确定数字i应处的位置;
*从数字i应处的位置开始,向后查找数字i现在的位置;
*若数字i现在位置不正确,则将数字i从现在的位置(沿连线)移向中间的空格,而将原有位置空出;依次将现有空格前的所有元素向后移动;直到将i应处的位置空出,把它移入再次空出中间的格.
从数字2开始使用以上过程,就可以完成全部数字的移动排序.
编程时要将矩阵的外边八个格看成一个环,且环的首元素是不定的,如果算法设计得不好,程序中就要花很多精力来处理环中元素的前后顺序问题.将题目中的3X3矩阵用一个一维数组表示,中间的元素(第四号)刚好为空格,设计另一个指针数组,专门记录指针外八个格构成环时的连接关系.指针数组的每个元素依次记录环中数字在原来数组中对应的元素下标.这样通过指针数组将原来矩阵中复杂的环型关系表示成了简单的线性关系,从而大大地简化了程序设计.
*程序说明与注释
#include<stdio.h>
int a[]={0,1,2,5,8,7,6,3}; /*指针数组.依次存入矩阵中构成环的元素下标*/
int b[9]; /*表示3X3矩阵,b[4]为空格*/
int c[9]; /*确定1所在的位置后,对环进行调整的指针数组*/
int count=0; /*数字移动步数计数器*/
int main()
{
int i,j,k,t;
void print();
printf("Please enter original order of digits 1~8:");
for(i=0;i<8;i++)
scanf("%d",&b[a[i>);
/*顺序输入矩阵外边的8个数字,矩阵元素的顺序由指针数组的元素a[i]控制*/
printf("The sorting process is as felow:\n");
print();
for(t=-1,j=0;j<8&&t==-1;j++) /*确定数字1所在的位置*/
if(b[a[j>==1) t=j; /*t:记录数字1所在的位置*/
for(j=0;j<8;j++) /*调整环的指针数组,将数字1所在的位置定为环的首*/
c[j]=a[(j+t)%8];
for(i=2;i<9;i++) /*从2开始依次调整数字的位置*/
/*i:正在处理的数字,i对应在环中应当的正确位置就是i-1*/
for(j=i-1;j<8;j++) /*从i应处的正确位置开始顺序查找*/
if(b[c[j>==i&&j!=i-1) /*若i不在正确的位置*/
{
b[4]=i; /*将i移到中心的空格中*/
b[c[j>=0;print(); /*空出i原来所在的位置,输出*/
for(k=j;k!=i-1;k--) /*将空格以前到i的正确位置之间的数字依次向后移动一格*/
{
b[c[k>=b[c[k-1>; /*数字向后移动*/
b[c[k-1>=0;
print();
}
b[c[k>=i; /*将中间的数字i移入正确的位置*/
b[4]=0; /*空出中间的空格*/
print();
break;
}
else if(b[c[j>==i) break; /*数字i在正确的位置*/
}
void print(void) /*按格式要求输出矩阵*/
{
int c;
for(c=0;c<9;c++)
if(c%3==2) printf("%2d ",b[c]);
else printf("%2d",b[c]);
printf("----%2d----\n",count++);
}
*运行结果
*问题的进一步讨论
很显然,按照上述算法都能解决问题,但移动的步数并不是最少的。
注意算法中的两个问题。其一:数字1的位置自始自终是保持不变的;其2:没有考虑到初始情况下,位置原本就已经是正确的数字。如例中的数字5和6,按照算法,当移动其它数字时,5和6了要跟着移动多次,这显然费了不少步数。
对于实例,若让数字1参与其它数字的移动排序过程,并充分利用数字5和6初始位置已经正确这一条件,可以大大优化移动排序的过程。
*思考题
请重新设计算法,编写更优化的程序,尽可能减少移动的步数。