NOIP2014普及组复赛 螺旋矩阵
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
NOIP2014普及组复赛试题解答
3. 螺旋矩阵
【问题描述】
一个n 行n列的螺旋矩阵可由如下方法生成:
从矩阵的左上角(第1行第1列)出发,初始时向右移动:如果前方是未曾经过的格子,则继续前进,否则右转;重复上述操作直至经过矩阵中所有格子。根据经过顺序,在格子中依次填入1,2,3,…,n2,便构成了一个螺旋矩阵。
现给出矩阵大小n以及i和j,请你求出该矩阵中第i行第j列的数是多少。
【分析】
这是个蛇形填数问题。如果采用先枚举二维数组再找对应的元素方法,由于1 ≤n ≤30,000,需要建立一个 30,000× 30,000的二维数组,结果会发生数据溢出且超出运行内存上限(128M)。
我们可以采用类似贪吃蛇的方法,让它在N×N个方格内自外向内逐格移动,控制其向右转的方向,并计算其长度。
解法一
#include
using namespace std;
bool pd(int,int) ;
int i,j;
bool p;
int main()
{
int n,x,y,u,d,l,r,tot=0; // U为上边界,D为下边界,L为左边界,R为右边界;
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
scanf("%d%d%d",&n,&i,&j);
d=n;r=n;u=1;l=1; //各边界赋初值;
x=1;y=0;
p=true;
while((tot { while((y while((x while((y>l)&&p){--y;++tot;pd(x,y);}++l;//在下侧边界上向左移动,当下侧一行的结束时,控制其左边界向右缩一列; while((x>u+1)&&p){--x;++tot;pd(x,y);}++u;//在左侧边界上向上移动,当左侧一列的结束时,控制其上边界向下缩一行; } printf("%d\n",tot); fclose(stdin);fclose(stdout); return 0; } bool pd(int x,int y) //判断是否到达目的地,如果到达则停止枚举; { if((x==i)&&(y==j))p=false; return p; } 解法二: 在上一个解法中,如果遇到极端情况时,可能需要枚举达900000000次,这显然太慢了些,我们可以根据贪吃移动的特点对程序进行优化。 可以这样考虑,当贪吃蛇到每个行列的转折点时,可以先判断目的地是否在自己的正前方,如果是则只需计算当前位置到目的地的距离加上自身的长度即可;否则就计算到下一个转折点人距离,加上当前自身长度,并到达下一个转折点,同时控制所在行(或列)的边界向内侧移动; #include using namespace std; bool pd(int,int) ; int main() { int n,i,j,x,y,u,d,l,r,tot=1; // U为上边界,D为下边界,L为左边界,R为右边界; freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout); scanf("%d%d%d",&n,&i,&j); d=n;r=n;u=1;l=1; //各边界赋初值; x=1;y=1; bool p=true; while(p) { if(p) if(x==i) //在上侧边界线上向右移动。如果目的地在正前方,则当前长度加上当前位置到目的地距离,结束循环; {tot=tot+j-y;p=false;} else //否则,当前长度加当前位置至行未的长度,同时到达右边界位置,并控制其上边界向下移动一列; {tot=tot+r-y;y=r;++u;} if(p) if(y==j) {tot=tot+i-x;p=false;} else {tot=tot+d-x;x=d;--r; } if(p) if(x==i) {tot=tot+y-j;p=false;} else {tot=tot+y-l;y=l;--d; } if(p) if(y==j) {tot=tot+x-i;p=false;} else {tot=tot+x-u;x=u;++l;} } printf("%d\n",tot); fclose(stdin);fclose(stdout); return 0; } 解法三: 对解法二,我们还可以进行优化。考虑到贪吃蛇总是从外围一圈圈地向目的地前进,而每一圈刚好是一个正方形,我们可以先计算外围各圈正方形的周长之和,再让贪吃蛇从目的地所在圈的左上角出发,计算其从出发地到目的地的长度就可以了。 #include using namespace std; bool pd(int,int) ; int main() { int n,i,j,x,y,u,d,l,r,k,t,tot=0; // U为上边界,D为下边界,L为左边界,R为右边界; bool p=true; freopen("matrix.in","r",stdin); freopen("matrix.out","w",stdout); scanf("%d%d%d",&n,&i,&j); x=i y=j k=x u=k;l=k;d=n-k+1;r=n-k+1; //设定各边界; for(t=1;t {tot=tot+(n-1)*4;n=n-2;} //计算在到达目的地外围所有圈的周长之和; x=k;y=k;++tot; //进入目的地所在的那一圈,初始化出发地; if(p) if(x==i) //向右移动。如果目的地在正前方,则当前长度加上当前位置到目的地距离,结束循环; {tot=tot+j-y;p=false;}