# [a020 身分證檢驗](https://zerojudge.tw/ShowProblem?problemid=a020)
## Problem Description
我國的身分證字號有底下這樣的規則,因此對於任意輸入的身分證字號可以有一些基本的判斷原則,請您來判斷一個身分證字號是否是正常的號碼(不代表確有此號、此人)。
(1) 英文代號以下表轉換成數字
A=10 台北市 J=18 新竹縣 S=26 高雄縣
B=11 台中市 K=19 苗栗縣 T=27 屏東縣
C=12 基隆市 L=20 台中縣 U=28 花蓮縣
D=13 台南市 M=21 南投縣 V=29 台東縣
E=14 高雄市 N=22 彰化縣 W=32 金門縣
F=15 台北縣 O=35 新竹市 X=30 澎湖縣
G=16 宜蘭縣 P=23 雲林縣 Y=31 陽明山
H=17 桃園縣 Q=24 嘉義縣 Z=33 連江縣
I=34 嘉義市 R=25 台南縣
(2) 英文轉成的數字, 個位數乘9再加上十位數的數字
(3) 各數字從右到左依次乘1、2、3、4....8
(4) 求出(2),(3) 及最後一碼的和
(5) (4)除$10$ 若整除,則為 real,否則為 fake
例: T112663836
2 + 7*9 + 1*8 + 1*7 + 2*6 + 6*5 + 6*4 + 3*3 + 8*2 + 3*1 + 6 = 180
除以 10 整除,因此為 real
##### 輸入說明
輸入共一行。每一行包含一組身分證號碼
##### 輸出說明
每讀入一行身分證字號,輸出 real or fake
##### 範例輸入/輸出
| 輸入 | 輸出 |
| -------- | ------------ |
| `T112663836` | `real` |
| `S154287863` | `fake` |
---
## 解題思路
這題需要用到[字元與字串](https://hackmd.io/@letscoding/Bk543geFw),如果不熟悉的同學可以先讀完筆記再來實作。
### 輸入
這題的輸入包含英文與數字,又要將每一位數個別處理計算,因此以字串讀入是較好選擇。若對字串處理不熟悉,可參考[字串與字元陣列](https://hackmd.io/@letscoding/Bk543geFw#%E5%AD%97%E4%B8%B2%E8%88%87%E5%AD%97%E5%85%83%E9%99%A3%E5%88%97)。
### 處理與輸出
輸入字串後,要針對各字元進行處理,並將結果進行加總。可以分為**數字處理**與**字母處理**
- 數字處理較為簡單,只要透過`c-'0'`轉換為數字再針對所在位數乘上數字即可。
- 較麻煩的部分是開頭的**字母處理**,如果 `A~Z` 有"依序"對應到 $10$~$35$,那或許可以透過
`c-'A'+10` 換算而得。但很不幸的並不是,但我們仍然不用透過26個`if - else if - else`或是`switch case`處理。我們依然可以透過以下兩個方法簡化程式。
#### 分段處理-尋找有限的規律
雖然沒有完全按照順序,但我們還是可以發現其中有一部分的對應表有照順序。我們可以分段處理:
| 字母 | 數字 | 字母 | 數字 |
|:----:|:-----:|:----:|:-----:|
| A-H | 10~17 | P-V | 23~29 |
| I | 34 | W | 32 |
| J-N | 18~22 | X-Y | 30~31 |
| O | 33 | Z | 35 |
所以我們可以透過8個`if - else if - else`簡化
#### 利用陣列建表
當對應的規則完全不按順序時,我們可以自己利用陣列建立一個對應表。初始化時依A\~Z的順序填入對應的值,再利用`c-'A'`將 A\~Z 轉換為 0\~25 後,即可在對應表中取得值。
---
## Sample Code
:::spoiler 分段處理
```cpp=
#include <iostream>
#include <string>
using namespace std;
int main(){
//輸入字串
string s;
cin >> s;
//計算
int p = 0; //從英文字母找到對應數字
if(s[0] <= 'H')
p = s[0]-'A' + 10;
else if(s[0] == 'I')
p = 34;
else if(s[0] <= 'N')
p = s[0]-'J' + 18;
else if(s[0] == 'O')
p = 35;
else if(s[0] <= 'V')
p = s[0]-'P' + 23;
else if(s[0] == 'W')
p = 32;
else if(s[0] <= 'Y')
p = s[0]-'X' + 30;
else
p = 33;
int num = p/10 + (p%10)*9;
for(int i = 1; i < 9; i++){
num += (s[i]-'0') * (9-i);
}
num += s[9]-'0';
//判斷並輸出
if(num % 10 == 0)
cout << "real" << endl;
else
cout << "fake" << endl;
}
```
:::
:::spoiler 建立對應表
```cpp=
#include <iostream>
#include <string>
using namespace std;
int main(){
//建立A~Z對應的數字表
int table[26] = {
10, 11, 12, 13, 14, 15, 16, 17, 34,
18, 19, 20, 21, 22, 35, 23, 24, 25,
26, 27, 28, 29, 32, 30, 31, 33
};
//輸入字串
string s;
cin >> s;
//計算
int p = table[s[0]-'A']; //從英文字母找到對應數字
int num = p/10 + (p%10)*9;
for(int i = 1; i < 9; i++){
num += (s[i]-'0') * (9-i);
}
num += s[9]-'0';
//判斷並輸出
if(num % 10 == 0)
cout << "real" << endl;
else
cout << "fake" << endl;
}
```
:::
---
## 進階挑戰
學會了嘛?趕快試試看類似題-[a054_電話客服中心](https://zerojudge.tw/ShowProblem?problemid=a054)