螺旋矩陣 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

代碼二:(這個代碼缺陷在於循環時間沒減少……)

 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)時間的算法。)

 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

 

關於計算層數的代碼:

其實是把整個數組分為左上、右上、左下和右下四個區域分別處理。

 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了。”

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM