关于这个二维数组填数问题我碰到过很多次,不管是找工作笔试面试,还是在算法竞赛,而且这种问题都有很多种变形,当初学算法的时候让我很是头疼,因为总是会了一道后,过了一段时间就忘了,又或者是这道会了,然后变了一下就不会了,我很是苦恼啊,不过当我某天在qq群中看到一个群友发的这种问题后,一下勾起了我的思考,然后不知道怎的,我就自己想出了一种方法,我觉得这个方法可以用在这种问题的任意一个地方,所以我觉得很好,然后我也就写篇博客总结一下吧,这个套路我是从BFS上汲取出来的,话不多说直接开始。
我总结这些题的总体都是按照一定的方向循环填数的,然后就按照一个方向不断地前进,只要碰到了边界或者下一个位置已经被填充过了那就换一个方向继续走继续填充,直到达到cnt的大小
int cnt = 1;
int dir[4][2] = {0,1,0,-1,1,0,-1,0};
int x = 0, y = 0;
matrix[x][y] = cnt++; // matrix初始都置为0
while(cnt <= N)
{
for(int i = 0; i < 4; ++i)
{
while(1)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(x < 0 || x >= n || y < 0 || y >= n) break; // 碰到边界
if(matrix[x][y]) break; // 已经填充过了
x = nx, y = ny;
matrix[x][y] = cnt++;
}
}
}
输入两个整数 n 和 m,输出一个 n 行 m 列的矩阵,将数字 1 到 n×m 按照回字蛇形填充至矩阵中。
具体矩阵形式可参考样例。
输入格式
输入共一行,包含两个整数 n 和 m。
输出格式
输出满足要求的矩阵。
矩阵占 n 行,每行包含 m 个空格隔开的整数。
数据范围
1≤n,m≤100
输入样例:
3 3
输出样例:
1 2 3
8 9 4
7 6 5
#include <cstdio>
#include <iostream>
using namespace std;
int dir[4][2] = {0,1,1,0,0,-1,-1,0};
const int N = 110;
int a[N][N];
int n, m, cnt = 1;
int main()
{
scanf("%d%d", &n, &m);
int x = 0, y = 0;
a[x][y] = cnt++;
while(cnt <= n * m)
{
for(int i = 0; i < 4; ++i)
{
while(1)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(nx < 0 || nx >= n || ny < 0 || ny >= m) break;
if(a[nx][ny]) break;
x = nx, y = ny;
a[x][y] = cnt++;
}
}
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
printf("%d ", a[i][j]);
}
puts("");
}
return 0;
}
可以看出是全部正确的
这个是一种斜线的走,只要把方向变一下,就行了,然后其余的这种都是一样的,只不过是方向的不同而已,其他的都是一样的
方阵的主对角线之上称为“上三角”。
请你设计一个用于填充n阶方阵的上三角区域的程序。填充的规则是:使用1,2,3….的自然数列,从左上角开始,按照顺时针方向螺旋填充。
例如:当n=3时,输出:
1 2 3
6 4
5
当n=4时,输出:
1 2 3 4
9 10 5
8 6
7
当n=5时,输出:
1 2 3 4 5
12 13 14 6
11 15 7
10 8
9
程序运行时,要求用户输入整数n(3~20)
程序输出:方阵的上三角部分。
要求格式:每个数据宽度为4,右对齐。
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 25;
int a[N][N];
int n, cnt = 1;
int dir[3][2] = {0,1,1,-1,-1,0}; // 右 左下 上
int main()
{
scanf("%d", &n);
int x = 0, y = 0;
a[x][y] = cnt++;
while(cnt <= (n+1) * n / 2)
{
for(int i = 0; i < 3; ++i)
{
while(1)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(nx < 0 || nx >= n || nx < 0 || ny >= n) break;
if(a[nx][ny]) break;
x = nx, y = ny;
a[x][y] = cnt++;
}
}
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(a[i][j]) printf("%4d",a[i][j]);
}
puts("");
}
return 0;
}
可以看出都是正确的
题目描述
给定两个数字 n 和 m,代表矩阵的大小。现有一个二维数组,需要对其进行填充。填充规律如下图:
输入描述
输入只有一行,第一个数字是 n,第二个数字是 m.
输出描述
请输出整个二维数组。每行末尾的数字后没有空格。
输入示例
3 4
输出示例
12 11 10 9
3 2 1 8
4 5 6 7
数据范围:
1 <= n <= 100;
1 <= m <= 100;
n 和 m 可能相等,也有可能不相等。
这个有点讨厌是从里到外一层一层填,我最初是按模板写的,发现不对,因为他是一层一层往外走的,不是走到边界或者碰到填过了的,就跟下图一样,这就麻烦得很,因为我不知道每一层的边界是多少,然后我就点开讨论区,看见了从外到内这四个字,一下就明白了,就从外向内跟那个回型填充一样,只不过cnt是从n*m开始了,见代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 110;
int matrix[N][N];
int n, m;
int dir[4][2] = {0,1, 1,0, 0,-1, -1,0}; // 分别为右 下 左 上
int cnt;
int main()
{
scanf("%d%d", &n, &m);
int x = 0, y = 0;
cnt = n * m;
matrix[x][y] = cnt--;
while(cnt > 0)
{
for(int i = 0; i < 4; ++i)
{
while(1)
{
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(nx < 0 || nx >= n || ny < 0 || ny >= m) break;
if(matrix[nx][ny]) break;
x = nx, y = ny;
matrix[x][y] = cnt--;
}
}
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < m; ++j)
{
printf("%d ", matrix[i][j]);
}
puts("");
}
return 0;
}
可以看出样例是正确的,然后也AC了