[蓝桥杯]回形取数---C++版---详细记录

题目 1465: [蓝桥杯][基础练习VIP]回形取数

时间限制: 1Sec 内存限制: 128MB
题目描述
回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度。一开始位于矩阵左上角,方向向下。
输入
输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列。接下来m行每行n个整数,表示这个矩阵。
输出
输出只有一行,共mn个数,为输入矩阵回形取数得到的结果。数之间用一个空格分隔,行末不要有多余的空格。
样例输入

3 3
1 2 3
4 5 6
7 8 9

样例输出

1 4 7 8 9 6 3 2 5


个人做题心得:
这是一道看似很简单,实则还行,操作下饭,debug难受的题目。

题目解析:
这道题目和之前记录的兰顿蚂蚁有些许相似之处,这样的一个回形取数就像蛇形取数一样。
讲讲自己的思路:
做题的几个点:

  • 回形取数—>蛇形走位,走位有方向,所以应该有char 类型的字符,来标记方向。
  • 同时,这个蛇向前进是根据头朝的方向,向前进。也就是说头朝哪里,就往哪里走。不同的朝向有不同的前进方式(这主要是xy坐标变换的方式不同)。
  • 如何决定什么时候转向 / 转向的条件是什么。
    从左上角开始以向下建立坐标系。
    下面来演示一下样例的给的基本路径:
    (0,0)->(1,0)->(2,0)---->(2,1)->(2,2)---->(1,2)->(0,2)->(0,1)---->(1,1)
    遇到转向的情况,我用加粗加长的线标出
    那么可以知道,如果朝着当前方向前行,到了下一个点,发现越界了,应该转向。但是此刻转向后还是在越界的点,所以还需要回退到原来的点。
    比如(2,0)->(3,0),(3,0)这个点不在给定的数组内,越界了,所以需要转向。此刻方向朝着右边,但是还在(3,0)这个点,所以应该回退到(2,0)这个点,再继续朝着头的朝向方向前进。
  • 外圈走完后,要进入内圈,此时判断转向的条件不再是越界问题,而是考虑是否被访问的情况。比如(0,1)->(1,1)这个点,这个点发生转向,不是因为越界问题,而是因为在方向不改变的情况下,(0,1)的下一个点是(0,0)。但是(0,0)是开始取数的点,已经取过数(即已访问),所以这时候应该左转,往内圈走。
    所以这个的转向条件就是下一个点是否被访问。转向,回退的道理和上一个点的理解方法一致。

接下来是源代码(有不懂的可以留言):

#include
using namespace std;
int m,n;	
int a[205][205];
int visit[205][205]={0};//访问数组	
int num;
int x=0,y=0;
char s='D'; 
void turn1()// 向左转
{
	switch(s)
	{
		case 'U': s='L'; break;
		case 'R': s='U'; break;
		case 'D': s='R'; break;
		case 'L': s='D'; break;
	}	
}
void go()//朝着当前头朝向前行1 
{
	switch(s)
	{
		case 'U': x--;  break;
		case 'R': y++;  break;
		case 'D': x++;  break;
		case 'L': y--;  break;
	}
} 
void back()//回退函数,用于返回上一个点,这里要注意xy的变化是根据转向前的情况来的 
{
	switch(s)
	{
		case 'U': y--;  break;
		case 'R': x--;  break;
		case 'D': y++; break;
		case 'L': x++;  break;
	}
}
void circle()
{
	while(num--)
	{
		if(x<m&&x>-1&&y<n&&y>-1&&visit[x][y]==0)//如果不越界且未被访问 
		{
			cout<<a[x][y]<<" ";//取数 
			visit[x][y]=1;//标记已访问 
			if(num==0)break;//步数 
		}
		go();
		if(visit[x][y]!=0)//如果已经标记就转向 
		{
			turn1();//转向 
			back();//回退 
			num++;//因为回退后的尝试情况也耗费步数,所以为了正常取数,耗费的步数要加上 
		}	
		else if((x>m-1||x<0)||(y>n-1||y<0))//越界就转向 
		{
			
			turn1();
			back();
			num++;
			continue;
		}
		else continue;
		
	}
} 
int main()
{

	cin>>m>>n;
	num=m*n;
	for(int i=0;i<m;i++)
	{
		for(int j=0;j<n;j++)
		{
			cin>>a[i][j];
		}
	}
	circle();
}

这题目debug弄了好久,思想不难。
建议:
先把思路弄透彻了再考虑改代码,不然一会一个主意一会儿一个主意的改代码,真的极费时间。

你可能感兴趣的:(#,刷题,算法,c++)