背景
从现在开始准备写一个关于我学习《算法竞赛-入门经典》学到的一些知识点的系列博客。
蛇形填数
题目描述
题目描述:
给定一个 n , 在 n * n 的方阵中填入 1 ,2, 3,……,n * n, 要求填成蛇形。
例如在 n = 5 时 , 如下所示:
13 14 15 16 1
12 23 24 17 2
11 22 25 18 3
10 21 20 19 4
9 8 7 6 5
思路:
- 首先构造操作环境:声明一个足够大的二维数组:a[maxn][maxm]
- 蛇形填数,顾名思义就是像蛇的形状一样对数组进行填数,理解成从“1”依次开始。设“笔”的坐标是(x,y)则一开始的坐标是x=0,y=n-1即(0,n-1);“笔”的移动轨迹就是“下 下 下……左 左 左……上 上 上……右 右 右……”,就是先朝着一个方向走,直到不能走了(这里是有条件的),再换个方向继续走。
不能走有两种情况
2.1: 到达蛇形填数形成矩阵的边界了,再继续走就越界了(即使数组没越界)。举个例子,比如题目中给定了初始数字n=5,那么从1开始往下走,走到5就不能继续往下写6(如果继续往下写6,就不能构成一个55的蛇形矩阵了),即使数组声明的是1010的数组空间。
2.2:继续走就要走到已经填过的格子了;再拿本题题目中给的例子,比如从16往下走,填到19就不能继续往下走了,往下走就是已经填过的6了。
题目总结:
范例代码:(main函数部分)
int main(){
int n,x,y,tot=0;
scanf("%d",&n);
memset(a,0,sizeof(a));//数组清零
tot=a[x=0][y=n-1]=1;
while(tot<n*n){
while(x+1<n && !a[x+1][y]) a[++x][y]=++tot;//从最后一列往下走
while(y-1>=0 && !a[x][y-1]) a[x][--y]=++tot;//从最后一行往右走
while(x-1>=0 && !a[x-1][y]) a[--x][y]=++tot;//从第一列往上走
while(y+1<n && !a[x][y+1]) a[x][++y]=++tot;//从第一行往右走
}
//打印输出
for(x=0;x<n;x++){
for(y=0;y<n;y++)
printf("%3d",a[x][y]);
printf("\n");
}
反思及总结
主要的原则是:先判断再移动。
拿内层的一个while循环来说:
while(x+1<n && !a[x+1][y]) a[++x][y]=++tot;//从最后一列往下走
先判断x+1<n 且 !a[x+1][y] ,先做预判,即是否越界,针对了以上所说的两种不能走的情况。
拓展一个知识点
“&&” 是短路运算符,什么意思呢?
while(x+1<n && !a[x+1][y]) a[++x][y]=++tot;//从最后一列往下走 这行代码中如果x+1<n为假,就不会计算 !a[x+1][y],因此,不用担心当x+1<n为假时,会造成 !a[x+1][y]的访问非法内存问题。