打印
Z字型扫描(有的又叫这是蛇形扫描)
https://www.acwing.com/problem/content/description/3211/
方法一:处在同一对角线(东北指向)上的点 之 行坐标+纵坐标 的和相等,且就是对角线序号
n * n 方阵有2*n-1条对角线,遍历行号,同时根据对角线确定列号(处在同一对角线(东北指向)上的点 之 行坐标+纵坐标 的和相等,且就是对角线序号)
一个矩阵一共有 2n−12n−1 条对角线
把对角线分成两类 右上和左下
对于每一条对角线 都有 x+y=C1 x−y=C2
也就是说 ,对角线的坐标之差/坐标之和是固定的
因此可以利用这个关系来算坐标 最后判断一下边界即可
由于Z字型扫描规律,偶序号对角线上扫描方向是 右上,行号递减;奇序号对角线上扫描方向是 左下,行号递增;
(改变遍历行号的顺序就行)
#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
int a[505][505];
int main(int argc, char** argv) {
int n;
cin>>n;//n*n矩阵
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
}
}
int len=(n<<1)-1;
//n方矩阵有2*n-1条对角线,根据这题扫描顺序,对角线沿着东北方向
for(int i=0;i<len;i++){//
if(i&1){//奇数号对角线从右上到左下输出 行号增大 偶数号对角线反之
for(int j=0;j<=i;j++){
if(j>=0&&j<n&&i-j>=0&&i-j<n)
cout<<a[j][i-j]<<" ";
//对角线序号固定不变,要输出这一对角线上所有元素,行列都在递变
//因此要用一个变量遍历 行,再根据 行号和对角线遍历 列号
}
}
else{
for(int j=i;j>=0;j--){
if(j>=0&&j<n&&i-j>=0&&i-j<n)
cout<<a[j][i-j]<<" ";
}
}
}
return 0;
}
方法二:利用东北指向的对角线上的点 横纵坐标之和相等,可以把横纵坐标之和相等的点存储在邻接表adj【i+j】(一个vector < int > 类型的数组)里面
#include <iostream>
#include <vector>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
int a[505][505];
//vector<int> adj[1010];//一个vector数组连城的数组
vector<vector<int> > adj;//二维vector数组👍
int main(int argc, char** argv) {
int n;
cin>>n;//n*n矩阵
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
adj[i+j].push_back(a[i][j]);
}
}
//横纵坐标之和为偶数的一条对角线上所有点遍历方向是右上,
// 行号逐渐递减,可插入邻接表的顺序是行号递增,要把该vector数组
// 逆序输出
for(int i=0;i<2*n;i++){
if(i&1){
for(int k=0;k<adj[i].size();k++){
cout<<adj[i][k]<<" ";
}
}
else{
for(int k=adj[i].size()-1;k>=0;k--){
cout<<adj[i][k]<<" ";
}
}
}
return 0;
}
方法三:遍历完了一条对角线拐弯
#include <iostream>
#include <vector>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
int a[505][505];
vector<int> adj[1010];//一个vector数组连城的数组
int main(int argc, char** argv) {
int n;
cin>>n;//n*n矩阵
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
adj[i+j].push_back(a[i][j]);
}
}
int x=0;
int y=0;
int flag=1;//偶数对角线 右上x--,y++
while(x!=n||y!=n){
if(x<n&&y<n)cout<<a[x][y]<<" ";
if(flag)x--,y++;
else x++,y--;
if(x<0){
x=0;
flag=1-flag;
}
if(y<0){
y=0;
flag=1-flag;//相当于遍历完了一条对角线拐弯了这时
}
}
return 0;
}
方法四:
来源
有一点蛇形矩阵的感觉,依次有四种方向【向右/向左下/向下/向右上】,其中向右和向下每次走一步就要转变方向,而向左下和向右上都是走到越界才转向。直到走完 n×n 个数停止。注意走过的位置不能再走,由于矩阵元素都是正数,所以可以在走完每一步后将对应的元素置0用于标记已经走过
#include <iostream>
using namespace std;
const int N = 510;
int a[N][N], n;
int dx[4] = {0, 1, 1, -1}, dy[4] = {1, -1, 0, 1};
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
cin >> a[i][j];
int i = 0, j = 0, cnt = 0 , t = 0;
cout << a[i][j] << ' ';
cnt ++ ;
while (cnt < n * n)
{
int x = i + dx[t], y = j + dy[t];
// 未遍历过/未越界
if (a[x][y] && x >= 0 && x < n && y >= 0 && y < n)
{
i = x, j = y;
cout << a[i][j] << ' ';
a[i][j] = 0;
cnt ++ ;
if (t == 0 || t == 2) t ++ ; // 向右和向下走一步就要变向
}
else t = (t + 1) % 4; // 遍历过或者越界需要转向
}
cout << endl;
return 0;
}
Z字型
#include
#include
/run this program using the console pauser or add your own getch, system(“pause”) or input loop /
using namespace std;
int a[505][505];
int main(int argc, char argv) {
int n;
cin>>n;//nn矩阵
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
}
}
int len=n2-1;
for(int i=0;i<len;i++){
for(int k=i;k>=0;k–){
if(k>=0&&k<n&&i-k>=0&&i-k<n)
cout<<a[k][i-k]<<" ";
}
}
return 0;
}
逆时针回字型打印
这个回字型填数模板中有个错误,四个循环中的第一个循环的初始条件不能为空,一定要写成
i
−
−
i--
i−−,即i的初始值设置为-1
因为回字型填数要走很多个回字,是一定要缩圈的
否则在第一圈的最后一个数,会跳跃式的比上一个数大2,原因是,没有缩圈,
c
n
t
+
+
cnt++
cnt++再次覆盖了这个位置
#include <iostream>
/*run this program using the console pauser or add your own getch, system("pause") or input loop */
using namespace std;
int a[505][505];
int main(int argc, char** argv) {
int m,n;
cin>>m>>n;//m*n矩阵
int cnt=0;
int ub=0;
int db=m-1;
int lb=1;
//注意啦,走完一圈的最后一次判断界限要比实际界限大1
// 如果是顺时针走回字,那么最后一次从下往上 ub应该设置为0+1
int rb=n-1;
int i=0;int j=0;//i,j永远分别指向行、列
while(cnt<m*n){//逆时针回字
for(;i<=db;i++)a[i][j]=cnt++;//上到下
db--;//缩圈
i--;//纠正循环最后一次的越界
for(++j;j<=rb;j++)a[i][j]=cnt++;//从左到右
//注意循环开始的++j 从上到下最后一个就是从左到右第一个 已经输出了
rb--;
j--;
for(--i;i>=ub;i--)a[i][j]=cnt++;//从下到上
ub++;
i++;
for(--j;j>=lb;j--)a[i][j]=cnt++;//从右到左
lb++;
j++;
}
for(int i=0;i<m;i++){
for(int j=0;j<n;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
1106: 蛇形填数(回字型)
#include <iostream>
using namespace std;
int a[25][25];
int main(){
int n;
// cin>>n;//n*n
while(cin>>n){
int lb=0;
int rb=n-2;//最后一次是从右往左,边界提前缩1
int ub=0;
int db=n-1;
int i=-1;
int j=n-1;
int cnt=0;
while(cnt<n*n){
for(++i;i<=db;i++){
a[i][j]=++cnt;
}
i--;//纠正越界
db--;//缩圈
for(--j;j>=lb;j--){
a[i][j]=++cnt;
}
j++;
lb++;
for(--i;i>=ub;i--){
a[i][j]=++cnt;
}
i++;
ub++;
for(++j;j<=rb;j++){
a[i][j]=(++cnt);
}
j--;
rb--;
}
for(int x=0;x<n;x++){
for(int y=0;y<n;y++){
if(y!=n-1)cout<<a[x][y]<<" ";
else cout<<a[x][y];
}
cout<<endl;
// if(x!=n-1)cout<<endl;
}
}
return 0;
}
打印漏斗
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
char ch;
cin>>n;
// getchar();
cin>>ch;
if(n==1){
cout<<ch<<endl;
cout<<"0"<<endl;
return 0;
}
int k=1;//半个沙漏共多少行(不算一个的那行
// int sum=1;
while(true){
int s=(2*k+4)*k+1;
if(s>n)break;
else k++;
}
k--;
// cout<<k<<endl;
//上半部分,
for(int i=k;i>=1;i--){
for(int j=1;j<=k-i;j++)cout<<' ';
for(int j=1;j<=i*2+1;j++)cout<<ch;
// for(int j=1;j<=k-i;j++)cout<<' ';
cout<<endl;
}
for(int i=1;i<=k;i++)cout<<' ';
cout<<ch<<endl;
for(int i=1;i<=k;i++){
for(int j=1;j<=k-i;j++)cout<<' ';
for(int j=1;j<=i*2+1;j++)cout<<ch;
// for(int j=1;j<=k-i;j++)cout<<" ";
cout<<endl;
}
int x=n-((2*k+4)*k+1);
// if(x)
cout<<x;
return 0;
}
类似打印漏斗 —— 打印菱形图案
等腰三角形
在屏幕上输出以下图案
#include <stdio.h>
int main()
{
int i,j,k;
int n;
printf("input n:");
scanf("%d",&n);
for(i=1;i<n;i++)
{
for(j=1;j<=n-i;j++)
printf("%2c",' ');
for(k=1;k<=2*i-1;k++)
{
if(k==1 || k == 2*i-1)
{ printf("%2c",'*');continue; }
printf("%2c",' ');
}
printf("n");
}
for(i=1;i<=2*n-1;i++)
printf("%2c",'*');
return 0;
}