### [P2 蜜蜂觀察](https://zerojudge.tw/ShowProblem?problemid=m932) APCS第二題的題目有9成是[二維陣列](https://www.w3schools.com/cpp/cpp_arrays_multi.asp),此題也不例外,將資料存入陣列內,移動時通過判斷式更新位置。 將蜂巢擺正後(往左傾斜)就能存入二維的字元陣列,並且為了之後方便運算[^1],在蜂巢本身以外,多拓寬一格(左右+上下)作為邊界,因此根據題目m, n = 20的最大值設定,我們可以宣告: ```=C++ char a[22][22]; ``` 第一個輸入的蜂巢資料索引值為[1,1],配合初始化的設定,陣列沒有被輸入覆蓋的地方皆為牆壁。 ```=C++ 例1 0000000... 0TyuI00... 0ABaB00... 0000000... 000... ..... ``` 題目的第二項要求是經過字元的種類數(大小寫視為相異),這裡我們宣告和維護兩個整數陣列,atoz[26]和AtoZ[26],代表各個字母出現的次數,最後統計若出現次數大於0,則種類數加一。 例:若a[i][j]為'b','b'-'a'為1,atoz[1]+=1。 #### 完整Code: ```=C++ #include <iostream> using namespace std; int main() { int m, n, k; cin >> m >> n >> k; char a[22][22]; //初始化 a for(int i=0;i<=21;i++){ for(int j=0;j<=21;j++){ a[i][j] = '0'; } } //input,(1,1)對應第一個值,(1,2)第二個... //當i=0,j=0,i=m+1,j=n+1時為牆壁('0') for(int i=1;i<=m;i++){ for(int j=1;j<=n;j++){ cin >> a[i][j]; } } int x = m, y = 1; //從左下角出發 int atoz[26]={0}; int AtoZ[26]={0}; int move; while(k--){ //(k=0, stop, k=k-1) cin >> move; int new_x = x, new_y = y; //新的位置 if(move == 1){ //右 new_y += 1; }else if(move == 4){ //左 new_y -= 1; }else if(move == 5){ //左上 new_x -= 1; new_y -= 1; }else if(move == 0){ //右上(實際是同一行,往上即可) new_x -= 1; }else if(move == 3){ //左下(實際是同一行,往下即可) new_x += 1; }else if(move == 2){ //右下 new_x += 1; new_y += 1; } if(a[new_x][new_y] != '0'){//牆壁 x = new_x; y = new_y; } cout << a[x][y]; if(a[x][y] >= 'a' && a[x][y] <= 'z'){ //小寫 atoz[a[x][y] - 'a'] += 1; }else{ //大寫 AtoZ[a[x][y] - 'A'] += 1; } } int ans = 0; for(int i=0;i<26;i++){ if(atoz[i]) ans++; if(AtoZ[i]) ans++; } cout << endl << ans; return 0; } ``` 若學過C++的容器[ set ](https://cplusplus.com/reference/set/set/)[^2],將經過的點丟入容器內,最後再輸出容器的大小即可,撰寫上快速很多。 ```=C++ #include <set> set<char> st; //走過的字母丟到這個集合內 while(... st.insert(a[x][y]); cout << endl << st.size(); ``` [^1]:若宣告剛好大小的陣列ex. m*n,在判斷邊界時需要多寫很多判斷式,也較容易因為陣列索引值超出範圍而導致錯誤 [^2]:set,功能相近於數學的"集合",元素不重複但是會經過排序。理論上不在APCS第二題的範圍內。