蛇形、之字、回字打印

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=n
2-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;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值