题目如下:
10 11 12 1
9 16 13 2
8 15 14 3
7 6 5 4
- 输入
- 直接输入方陈的维数,即n的值。(n<=100)
- 输出
- 输出结果是蛇形方陈。
- 样例输入
-
3
- 样例输出
-
7 8 1 6 9 2 5 4 3
PS:此题虽为算法入门题,但也耗费了我大半天的时间,说明我的水平还是有待提高!(哭)
分析:
在解决本题的过程中,我主要思考过两种方法:
1.直接暴力解决(虽然我的解法也挺暴力的):但是过于问题在于,循环不好写,而且适用范围不大。能轻而易举的写出每一个n的外圈数,但是涉及到内圈填数时并不好执行。
例如你很容易写出n=3,n=4甚至n=5的情形,但要适用范围广必须得要有相应变量的变化和循环。
2.找到各位置数与 n 之间的规律,比如我找到的,[0][0]=n+2*(n-1),[1][1]=[0][n-1]+3n-5并以此作为出发点来填数。但是结果也并不能如愿。
主要原因:随着n的变化,之前所总结出来的规律可能不适用,因为这个矩阵总是在变化的。---(也可能是我数学水平太差,总结不出来吧....)
***************************************************************************************************************************
后来我的思路是这样:
按照蛇形填数的要求,重新理了一遍排列思路。并带入程序语言进去进行推理。
后来我发现这个填数实质上是可以不断切割成若干小的蛇形填数,我想象成从外往内填入数字。
所以,就可以将一个大的填数过程分解成无数个小的,然后对他们进行循环。
#include<iostream>
using namespace std;
int main()
{
int n = 0;
cin >> n;//输入的n
int num[100][100];
int k = 0;//循环中进行缩小圈的大小所用变量,用来将表左边进行缩小
int i = 0;//表示纵坐标
int j = 0;//表示横坐标
int cnt = 0;//往表中填入的数
int scale = n * n;//作为while和if执行的判断语句
int N = n;//n在循环中会变化,N用来保存原始的n。n自减将右边进行缩小
while (cnt != (scale)) {
if (cnt !=(scale)) {
for (i = k; i < n; i++) {
j = n - 1;
++cnt;
num[i][j] = cnt;
}//总是先填最后列
--j;
--i;
}
if (cnt != (scale)) {
for (j; j >= k; j--) {
++cnt;
num[i][j] = cnt;
}//第二次填最下面一行
++j;
--i;
}
if (cnt !=(scale)) {
for (i; i >= k; i--) {
++cnt;
num[i][j] = cnt;
}//最左边一列
++i;
++j;
}
if (cnt != (scale)) {
for (j; j < n-1; j++) {
++cnt;
num[i][j] = cnt;
}//最上边一行
}
--n;
++k;//没填完一个圈,就缩小一次
}
//cout << 1 << endl;
i = 0;
j = 0;
for (i; i < N; i++) {
j = 0;
for (j; j < N; j++) {
cout << num[i][j] << " ";
}
cout << endl;
}
return 0;
}
这就是完整的代码。
特别值得注意的是每个行,列填写中的i与j是否越界的问题,要进行检查,并加以处理。
检查的方法很简单,加一个cout<<i<<endl<<j<<endl;就可以再测试时检查每一个i,j是否越界。
也可以用此方法检查cnt,n和k;
最后一点就是while和if的判断问题。想的简单一点,找到蛇形填数结束的规律,总是填到数为n*n时结束,so就将其当做判断条件。当然也有其他的判断条件,这里就不再赘述。
***************************************************************************************************************************
总结:
按照填数规律填数;
一圈填完后缩小表,采用n自减缩小右侧,k自加缩小左侧的方法;
注意i,j,数组不要越界;
判断条件:填入数!=n*n;