### [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第二題的範圍內。