第十三届蓝桥杯省赛模拟赛 螺旋矩阵(非for循环)

目前原题还没出来,只能凭印象把题目写下来,等过几天原题出来,我会把自己会的题和思路以及在论坛上总结的解法写一下,希望共同学习。

题目:求一个从1开始的30×30的螺旋矩阵的第20行第20列的数。

看到这题的第一眼就想到了刚刚学习的算法深度优先搜索,只要规定优先级(右下左上)就可以对二维数组进行螺线遍历,但是在实际运用中发现当走到数组左下角时:

第十三届蓝桥杯省赛模拟赛 螺旋矩阵(非for循环)_第1张图片

这时最大优先级是右,而右边刚好没有被标记,所以会向右遍历,并不是螺旋矩阵。所以深搜不能使用。

第十三届蓝桥杯省赛模拟赛 螺旋矩阵(非for循环)_第2张图片

之后再论坛上查找的方法都是使用四个for循环进行输出。

但是发现了一篇文章使用是通过一个方向变量来控制数组走向的方法:螺旋矩阵---易懂系列_Cosmic_Tree的博客-CSDN博客_螺旋矩阵

这里我写一下自己的理解,为自己加深一下印象。

思路:

每次把新的数字录入数组后对下个位置进行判断,判断是否“碰壁”(即越界),如果不是,那就按目前方向继续录入,如果是,那就换下一个方向进行录入。

方向优先级:右、下、左、上。

对方向的实现:

        对于二维数组(从左上角开始):

                向右的操作:行不变,列加一。

                向下的操作:行加一,列不变。

                向左的操作:行不变,列减一。

                向下的操作:行减一,列不变。

        那么我们就可以用两个一位数组记录每个方向每个坐标的变化量。

int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};
           //右,下,左,上

这样如果要对坐标进行变更,比如向右,就使x+dx[0],y+dy[0],向其他方向同理。

不难发现,右下左上分别对应的数组角标是0123。

那么我们定义一个d作为方向变量,初始值为0,每当判断“碰壁”,那就使d++,但是这样又出现一个问题:这个矩阵是螺旋的,那么它碰壁的次数肯定不止4次,当d=3时,再次碰壁那么d++之后d的值就是4了,这也很简单,只需对d取4的余数就可以了,那每次碰壁后的操作就是:

d = (d+1) % 4;

对于碰壁的判断:

if((tx+dx[d]>30||ty+dy[d]>30||ty+dy[d]<=0)||(a[tx+dx[d]][ty+dy[d]]))
	{
			d = (d+1) % 4;
	}

这里的“(tx+dx[d]>30||ty+dy[d]>30||ty+dy[d]<=0)”不难理解,(a[tx+dx[d]][ty+dy[d]])就是此螺旋矩阵,只要一开始把此二维数组初始化为0,如果a[x][y]的值为0那就等同于if(false)也就是不碰壁,如果不是0那就是true,也就是碰壁,进行转向操作。

题解:

#include

int a[31][31];
int i;


int dx[4] = {0,1,0,-1};
int dy[4] = {1,0,-1,0};


void arrinit()
{
	int tx = 1,ty = 1,d = 0;
	for(i = 1;i <= 900;i++)
	{
		if((tx+dx[d]>30||ty+dy[d]>30||ty+dy[d]<=0)||(a[tx+dx[d]][ty+dy[d]]))
		{
			d = (d+1) % 4;
		}
		a[tx][ty] = i;
		tx += dx[d];
		ty += dy[d];
	}
}

int main()
{
	arrinit();
	printf("%d",a[20][20]);
	
	return 0;	
} 

你可能感兴趣的:(c语言,蓝桥杯)