本題可以直接模擬填數字,也可以直接計算結果。
代碼一:(這個代碼,缺陷在於數組太大,浪費內存啊。另外,循環次數也不少。總之,時間空間的消耗都不小。)

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 }
代碼二:(這個代碼缺陷在於循環時間沒減少……)

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 }
代碼三:(這個代碼應該算是比較完美了,時間空間都降下來了,而且是O(1)時間的算法。)

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 }
關於計算層數的代碼:
其實是把整個數組分為左上、右上、左下和右下四個區域分別處理。

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 }
關於計算(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了。”