题目:
Input Height N, printf such pattern:
1 2 3 4 516 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
第一种解法:是用等差数列解题。
算法:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
定义N:图形高度
定义l:当前圈边长l
l(1)=N-1
l(r)=N-2*(r-1)-1设当前圈左上角为开始。定义d:当前行的方向(上边为0右边为1下边为2左边为3)
定义pl:当前圈当前边距角的长度(向数字小的方向)
定义a:当前圈共有多少个数字
a(r)=4*l(r)=4*(N-2*(r-1))-4
公差为-8
从最外圈到当前圈求和:s(r)=a(1)*r-r*(r-1)/2*(-8)
定义b:本圈第一个数字
b(r)=s(r-1)+1
=a(1)*(r-1)-(r-1)*(r-2)/2*(-8)+1
开始计算:
求r: r=min(i,N-j+1,N-i+1,j)
求d: d为(i,N-j+1,N-i+1,j)与r对应,如r如第1个值,则d为第一个值...
求pl: p=(j-r,i-r,N-j+1-r,N-i+1-r)与r对应,如r如第1个值,则d为第一个值...
当前数值b+l*d+pl
Commented by Wang Rui程序如下:
main( )
{ int i,j,r,l,b,d,pl,N;
printf("Input Height:"); /*输入高度*/
scanf("%d",&N);
for (i=1;i<=N;i++)
{ for (j=1;j<=N;j++) /*定位到第i行第j列*/
{ r=i;d=0;pl=j-r;
if (r>N-j+1) {r=N-j+1;d=1;pl=i-r;}
if (r>N-i+1) {r=N-i+1;d=2;pl=N-j+1-r;}
if (r>j) {r=j;d=3;pl=N-i+1-r;}
/*找出圈数,边的位置,在边上的位置*/
l=N-2*(r-1)-1;/*边长*/
b=(4*N-4)*(r-1)-4*(r-1)*(r-2)+1;
/*本圈开始的数字*/
printf("%4d",b+l*d+pl);/*打印数字*/
}
printf("\n");
}
}
第二种解法:这是用几何方法解的。
main( ){ int i,j,N,c;
printf("Input N=");
scanf("%d",&N);
for (i=1;i<=N;i++)
for (j=1;j<=N;j++)
{ if (j>=i&&j<=N+1-i||j<=i&&j>=N+1-i)
if (i<=(N+1)/2)
c=(i-1)*(4*N-4*i+3)+j;
else
c=2*(N-i)*(2*i-1)+3*i-j-1;
else
if (j<=(N+1)/2)
c=4*N*j-4*j*j-i+j+1;
else
c=(N-j)*(4*j-3)+N+i-1;
printf((j==N)?"%4d\n":"%4d",c);
}
}
第三种解法:用面积解。
main( )
{ int i,j,r,l,b,d,pl,N;
printf("Input Height:"); /*输入高度*/
scanf("%d",&N);
for (i=1;i<=N;i++)
{ for (j=1;j<=N;j++) /*定位到第i行第j列*/
{ r=i;d=0;pl=j-r;
if (r>N-j+1) {r=N-j+1;d=1;pl=i-r;}
if (r>N-i+1) {r=N-i+1;d=2;pl=N-j+1-r;}
if (r>j) {r=j;d=3;pl=N-i+1-r;}
/*找出圈数,边的位置,在边上的位置*/
l=N-2*(r-1);/*边长*/
b=N*N-l*l+1;/*用面积计算*/
/*本圈开始的数字*/
printf("%4d",b+(l-1)*d+pl);/*打印数字*/
}
printf("\n");
}
}
第4种解法。
分析:首先寻找数字输出数字和行列的关系。每圈有四个边,把每边的最后一个数字算为下边的开始,最外圈每边数字个数是n-1个,以后每边比外边一边少两个数字。
因为数字是一行一行输出的,再分析每行数字的规律。实际没有的数字有三种规律:位于对角线之间的数字是上半图增一,下半图减一。对角线左侧的各列,右侧比左侧增加了一圈数字,例如数字39和它左侧的22比较,数字39所在的圈每边4个数字,左侧22加上一圈16个数字在加1就是39。同理,对角线右侧的各列,则减少一圈的数字个数。
根据以上分析,用两个对角线将图形分为四个区域,如下图所示,图中黑斜体字为对角线上的数字。
1 2 3 4 5 6 7
24 25 26 27 28 29 8
23 40 41 42 43 30 9
22 39 48 49 44 31 10
21 38 47 46 45 32 11
20 37 36 35 34 33 12
19 18 17 16 15 14 13
为叙述方便我们称四个区域为上、下、左、右区。设i、j为行列号,n为图形的总行数,则满足各区的范围是:
上区:j>=i且j<=n-i+1 下区:j<=i且j>=n-i+1
左区:j<i且j<n-i+1 右区:j>i且j>n-i+1
现在问题是,如果知道一行在不同区域开始第一个位置的数字,然后该区后续的数字就可利用前面分析的规律得到。对于右区开始各行第一个数字最易求出,为4*(n-1)-i+1。后续一个和同行前一个数字之差是4*[n-1-(j-1)*2]+1,其中方括号内是每边的数字个数。对角线上的数字是分区点,对角线上相临数字仍然相差一圈数字个数,读者自行分析得到计算公式。右区开始的第一个数字可以从上区结束时的数字按规律求出。下述程序用变量s保存分区对角线上的数字。
参考答案:
main( )
{ int i,j,k,n,s,m,t;
printf("Please enter n:");
scanf("%d",&n);
for (i=1;i<=n;i++)
{ s = (i<=(n+1)/2)? 1:3*(n-(n-i)*2-1)+1;
m = (i<=(n+1)/2)? i:n-i+1; /* m-1是外层圈数 */
for (k=1;k<m;k++) s+=4*(n-2*k+1);
for (j=1;j<=n;j++)
{ if (j>=n-i+1 && j<=i) /* 下区 */
t=s-(j-(n-i))+1;
if (j>=i && j<=n-i+1) /* 上区 */
t=s+j-i;
if (j>i && j>n-i+1) /* 右区 */
t -= 4*(n-2*(n-j+1))+1;
if (j<i && j<n-i+1) /* 左区 */
{ if (j==1) t=4*(n-1)-i+2;
else t+=4*(n-2*j+1)+1;
}
printf("%4d",t);
}
printf("\n");
}
}
第5种解法:递归方法。
分析:根据本题图形的特点,我们可以构造一个递归算法。我们可以将边长为N的图形 分为两部分:第一部分最外层的框架,第二部分为中间的边长为N-2的图形。对于边长为N的正方型,若其中每个元素的行号为i(1≤i≤N),列号为j(1≤j≤N),第1行第1列元素表示为a1,1(a11=1),则有:对于最外层的框架可以用以下数学模型描述:
上边: a1,j=a1,1+j-1 (j≠1)
右边: ai,N=a1,1+N+i-2 (i≠1)
下边: ai,1=a1,1+4N-i-3 (i≠1)
左边: aN,j=a1,1+3N-2-j (j≠1)
对于内层的边长为N-2的图形可以用以下数学模型描述:
左上角元素:ai,i=ai-1,i-1+4(N-2i-1) (i>1)
若令:ai,j=fun(ai-1,i-1+4(N-2i-1),当:i<(N+1)/2且j<(N+1)/2时,min=MIN(i,j),则有:
a2,2 = fun(a1,1, min, min, n)
ai,j=fun(a2,2, i-min+1, j-min+1, n-2*(min-1) )
我们可以根据上述原理,分别推导出i和j为其它取值范围时的min取值。根据上述递归公式,可以得到以下参考程序。
#include <stdio.h>
#define MIN(x,y) (x>y) ? (y) : (x)
fun ( int a11, int i, int j, int n)
{ int min, a22;
if ( i==j && i<=1 ) return a11;
else if ( i==j && i<=(n+1)/2) return ( fun(a11,i-1,i-1,n)+4*(n-2*i+3) );
else if ( i==1 && j!=1 ) return ( a11+j-1 );
else if ( i!=1 && j==n ) return ( a11+n+i-2 );
else if ( i!=1 && j==1 ) return ( a11+4*n-3-i );
else if ( i==n && j!=1 ) return ( a11+3*n-2-j );
else
{ if (i>=(n+1)/2 && j>=(n+1)/2) min = MIN(n-i+1,n-j+1);
else if (i<(n+1)/2 && j>=(n+1)/2) min = MIN(i,n-j+1);
else if (i>=(n+1)/2 && j<(n+1)/2) min = MIN(n-i+1,j);
else min = MIN(i,j);
a22 = fun(a11,min,min,n);
return fun(a22, i-min+1, j-min+1, n-2*(min-1) );
}
}
main ( )
{ int a11=1, i, j, n;
printf ("Enter n=");
scanf("%d", &n);
for (i=1; i<=n; i++)
{ for (j=1; j<=n; j++)
printf ("%4d", fun(a11,i,j,n) );
printf ("\n");
}
}