NOIP2014普及组复赛 螺旋矩阵

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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;}

相关文档
最新文档