且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

螺旋矩阵 noip2014普及组

更新时间:2022-08-16 19:31:51

 

螺旋矩阵 noip2014普及组

螺旋矩阵 noip2014普及组

本题可以直接模拟填数字,也可以直接计算结果。

代码一:(这个代码,缺陷在于数组太大,浪费内存啊。另外,循环次数也不少。总之,时间空间的消耗都不小。)

螺旋矩阵 noip2014普及组螺旋矩阵 noip2014普及组
 1 /*===============================================================
 2 本段代码是模拟往数组填数字的过程。
 3 每填写一个值就判断该位置是否(i,j)。若寻到目标位置,
 4 则输出答案。 
 5 =================================================================*/
 6 #include<stdio.h>
 7 int a[3001][3001]={0};//这个大小的静态数组尚可申请,但假如是放在函数内部声明却不行了的。这个大小大概是9MB,但距离30000*30000的大小实在是太远了。 
 8 int main()
 9 {
10     int n,i,j;
11     int m;//m表示总共的层数 
12     int k,p,q;//循环变量 
13     int flag=0;//标志性变量:等于0表示尚未循环到目标元素(i,j) 
14     int t;
15      int len;
16      
17     scanf("%d%d%d",&n,&i,&j);
18     m=(n+1)/2;  //m表示总共的层数 
19     t=1;        //t表示要填进数组的数字
20     for(k=1;k<=m&&flag==0;k++)
21     {
22         p=k,q=k;      //(k,k)是第k层左上角坐标点
23         len=n-2*(k-1);//表示当前层中每一条边的元素个数 
24         for(;q<=(k+len-1);q++)//填充当前层的顶边 
25         {
26             a[p][q]=t;
27             if(p==i&&q==j)
28             {
29                 printf("%d\n",a[p][q]);
30                 return 0;
31             }
32             t++;
33         }
34         q--;
35         p++;
36         for(;p<=(k+len-1);p++)//填充当前层的右边 
37         {
38             a[p][q]=t;
39             if(p==i&&q==j)
40             {
41                 printf("%d\n",a[p][q]);
42                 return 0;
43             }
44             t++;
45         }
46         p--;
47         q--;
48         for(;q>=k;q--)//填充当前层的下边
49         {
50             a[p][q]=t;
51             if(p==i&&q==j)
52             {
53                 printf("%d\n",a[p][q]);
54                 return 0;
55             }
56             t++;
57         }
58         q++;
59         p--;
60         for(;p>k;p--)//填充当前层的左边
61         {
62             a[p][q]=t;
63             if(p==i&&q==j)
64             {
65                 printf("%d\n",a[p][q]);
66                 return 0;
67             }
68             t++;
69         }
70     }
71     return 0;
72 }
View Code

代码二:(这个代码缺陷在于循环时间没减少……)

螺旋矩阵 noip2014普及组螺旋矩阵 noip2014普及组
 1 /*===============================================================
 2 本段代码也是模拟往数组填数字的过程。但没有申请数组内存来存储数据。
 3 而是只用一个变量表示每一次要填写的数字。
 4 毕竟题目只要输出(i,j)位置的值,故不用保存整个数组。
 5 只需要判断每一次模拟到的位置是否是(i,j)即可。 
 6 =================================================================*/
 7 #include<stdio.h>
 8 int main()
 9 {
10     int n,i,j;
11     int m;//m表示总共的层数 
12     int k,p,q;//循环变量 
13     int flag=0;//标志性变量:等于0表示尚未循环到目标元素(i,j) 
14     int t;
15      int len;
16      
17     scanf("%d%d%d",&n,&i,&j);
18     m=(n+1)/2;  //m表示总共的层数 
19     t=1;        //t表示要填进数组的数字
20     for(k=1;k<=m&&flag==0;k++)
21     {
22         p=k,q=k;      //(k,k)是第k层左上角坐标点
23         len=n-2*(k-1);//表示当前层中每一条边的元素个数 
24         for(;q<=(k+len-1);q++)//填充当前层的顶边 
25         {
26             if(p==i&&q==j)
27             {
28                 printf("%d\n",t);
29                 return 0;
30             }
31             t++;
32         }
33         q--;
34         p++;
35         for(;p<=(k+len-1);p++)//填充当前层的右边 
36         {
37             if(p==i&&q==j)
38             {
39                 printf("%d\n",t);
40                 return 0;
41             }
42             t++;
43         }
44         p--;
45         q--;
46         for(;q>=k;q--)//填充当前层的下边
47         {
48             if(p==i&&q==j)
49             {
50                 printf("%d\n",t);
51                 return 0;
52             }
53             t++;
54         }
55         q++;
56         p--;
57         for(;p>k;p--)//填充当前层的左边
58         {
59             if(p==i&&q==j)
60             {
61                 printf("%d\n",t);
62                 return 0;
63             }
64             t++;
65         }
66     }
67     return 0;
68 }
View Code

代码三:(这个代码应该算是比较完美了,时间空间都降下来了,而且是O(1)时间的算法。)

螺旋矩阵 noip2014普及组螺旋矩阵 noip2014普及组
 1 /*===============================================================
 2 本段代码不是模拟填写数字的过程,而是直接根据i和j的值计算(i,j)所在的层k。
 3 然后计算第k层左上角(k,k)位置处的元素值。 
 4 接下来呢,要寻到 (i,j)处的值,可以有两种方法:
 5 (1)模拟填数字的过程环绕一圈寻找(i,j)。
 6 (2)根据i,j的值依次计算(k,k)距离(i,j)的几个段的距离即可得到答案。
 7 这里使用第二个方案。 
 8 =================================================================*/
 9 #include<stdio.h>
10 int main()
11 {
12     int n,i,j;
13     int k,t;
14     freopen("matrix10.in","r",stdin);
15     freopen("matrix10.txt","w",stdout);
16     scanf("%d%d%d",&n,&i,&j);
17     //根据i判断(i,j)所在层数k
18     t=(n+1)/2;
19     if(i<=t)
20     {
21         if(j<=t)  k=(i<=j?i:j);//(i,j)在左上部分
22         else k=(i<(n+1-j)?i:(n+1-j));  //(i,j)在右上部分 
23     }
24     else
25     {
26         if(j<=t) k=(n+1-i)<j?(n+1-i):j;   //(i,j)在左下部分 
27         else k=(n+1-i)<(n+1-j)?(n+1-i):(n+1-j);   //(i,j)在右下部分 
28     }
29     //计算第k层左上角坐标为(k,k)的数t
30     k--;
31     t=n*n-(n-2*k)*(n-2*k)+1;//注意:n-2k表示剥去k层之后剩余部分的行数和列数.(i,j)所在层没被剥掉,故而要先执行k--。 
32     k++;
33     if(i==k) //(i,j)在第k环的上边线 
34         t=t+(j-k);
35     else if(j==k+n-2*(k-1)-1) //(i,j)在环的右边.
36         t=t+(n-2*(k-1)-1)+(i-k);
37     else if(i==k+n-2*(k-1)-1)//(i,j)在环的下边 
38         t=t+(n-2*(k-1)-1)+(n-2*(k-1)-1)+((k+n-2*(k-1)-1)-j);
39     else t=t+(n-2*(k-1)-1)+(n-2*(k-1)-1)+(n-2*(k-1)-1)+((k+n-2*(k-1)-1)-i);
40     printf("%d\n",t);
41     return 0;
42 }
View Code

 

关于计算层数的代码:

其实是把整个数组分为左上、右上、左下和右下四个区域分别处理。

螺旋矩阵 noip2014普及组螺旋矩阵 noip2014普及组
 1 #include<stdio.h>
 2 int main()
 3 {
 4     int n,i,j,k,t;
 5     scanf("%d",&n);
 6     for(i=1;i<=n;i++)
 7     {
 8         for(j=1;j<=n;j++)
 9         {
10             t=(n+1)/2;
11             if(i<=t)
12             {
13                 if(j<=t)  k=(i<=j?i:j);//(i,j)在左上部分
14                 else k=(i<(n+1-j)?i:(n+1-j));  //(i,j)在右上部分 
15             }
16             else
17             {
18                 if(j<=t) k=(n+1-i)<j?(n+1-i):j;   //(i,j)在左下部分 
19                 else k=(n+1-i)<(n+1-j)?(n+1-i):(n+1-j);   //(i,j)在右下部分 
20             }
21             printf("%d ",k);
22         }
23         printf("\n");
24     }
25     return 0;
26 }
View Code

关于计算(i,i)处的值:

n*n-(n-2*k)*(n-2*k)+1

其中,n*n是数字总的个数,k是表示被剥去的层数(注意:假如(i,j)在第k层,则被剥去的是(k-1)层。)

(n-2*k)*(n-2*k)表示剥去之后,剩余部分的元素的个数。

如何理解n-2*k呢?其实啊,就是“每剥去一层,行和列的数量都会减少2,于是总共减少的数量就是2*k。剩余的部分自然就是n-2*k了。”