Try   HackMD

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 + 79 + 18 + 17 + 26 + 65 + 64 + 33 + 82 + 3*1 + 6 = 180

除以 10 整除,因此為 real

輸入說明

輸入共一行。每一行包含一組身分證號碼

輸出說明

每讀入一行身分證字號,輸出 real or fake

範例輸入/輸出
輸入 輸出
T112663836 real
S154287863 fake

解題思路

這題需要用到字元與字串,如果不熟悉的同學可以先讀完筆記再來實作。

輸入

這題的輸入包含英文與數字,又要將每一位數個別處理計算,因此以字串讀入是較好選擇。若對字串處理不熟悉,可參考字串與字元陣列

處理與輸出

輸入字串後,要針對各字元進行處理,並將結果進行加總。可以分為數字處理字母處理

  • 數字處理較為簡單,只要透過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

分段處理
#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; }
建立對應表
#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_電話客服中心