嗨,大家好,我是KevinLee,一位正在在轉職軟體工程師路上的遊戲技術美術。
為了能讓自己學習的過程更加深刻,決定開始在這邊記錄自己練習過的題目,方便未來學習更專精時,可以回頭審視自己所寫過的code,也請大家多多指教!
📅 2026/01/012
🏷️ C++、leetcode、Flow Control
✍️ KevinLee
🧩 Topic from "Zerojudge"
🎯 我國的身分證字號檢驗規則如下:
(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 + 7x9 + 1x8 + 1x7 + 2x6 + 6x5 + 6x4 + 3x3 + 8x2 + 3x1 + 6 = 180
180除以10整除,因此為"real"
/
輸入說明: 輸入共一行。每一行包含一組身分證號碼
輸出說明: 每讀入一行身分證字號,輸出 real or fake
範例輸入#1: T112663836
範例輸出#1: real
/
範例輸入#2: S154287863
範例輸入#2: fake
📜 邏輯紀錄
看完題目後,我習慣先將所需的變數一一整理並宣告,如下。首先,由於輸入只會有一行,因此宣告一個 string 來接收輸入內容。接著,題目在第 (4) 點中提到需要計算「和」,因此需要一個 int 變數來儲存累加結果。
在處理英文轉數字的部分,我第一時間聯想到可以利用 ASCII 進行轉換。不過進一步思考後發現,英文字母對應的 ASCII 十進位數值並不等於題目所定義的實際數字,例如字母 A 的 ASCII 為 65,但題目中定義A = 10,兩者並不相符。
因此,需要一個int變數來儲存每個英文字母轉換後的數值,於是宣告了一個ENASCII變數。同時觀察到 ASCII 值 65 與題目中的 10 之間相差 55,於是再宣告一個 int 作為偏移值,用來修正 ASCII 與題目數值之間的差距。
string ID;
int Total = 0;
int ENASCII = 0;
int offset = 0;
接著,需要輸入一個字串
cin >> ID;
(2)提到,英文轉成的數字, 個位數乘9再加上十位數的數字,公式如下:
將字串的第一個英文字母轉換成int,可透過int(ID[0])得到該字元的ASCII。
ENASCII = ((int(ID[0]) - offset) % 10) * 9 + (int(ID[0]) - offset) / 10;
(3),各數字從右到左依次乘1、2、3、4....8。這樣的規則非常適合透過迴圈來處理,如下: 由於這邊也是將string中的各個字元轉換成int,因此會遵循ASCII的規則,將字元數字轉換成ASCII,例如1的ASCII是49,因此,需要將其-48才能代表真實的數字。最後在進行(4)的規則,也就是(2)、(3)的總和。
for (int i = 0; i < 8; i++)
{
Total = Total + (int(ID[i + 1]) - 48) * (8 - i);
}
Total = Total + ENASCII + (int(ID[9]) - 48);
(5)提到,將(4)除10 若整除,則為 real,否則為 fake,也就是將Total % 10 = 0即可判斷real or fake。
if (Total % 10 == 0)
{
cout << "real" << endl;
}
else
{
cout << "fake" << endl;
}
最後,在檢視英文轉數字的轉換規則後可以發現,A ~ Z 所對應的數值並非單純依序遞增,因此各字母所需的偏移值也不盡相同。不過,由於這組對應關係是固定且明確的,在本次實作中,我選擇以最直覺的方式,透過條件式將轉換規則直接寫死來處理。
int ID_Rule(string ID)
{
int offset = 0;
if (ID[0] == 'A' || ID[0] == 'B' || ID[0] == 'C' || ID[0] == 'D' || ID[0] == 'E' || ID[0] == 'F' || ID[0] == 'G' || ID[0] == 'H' || ID[0] == 'W')
{
offset = 55;
}
else if (ID[0] == 'I')
{
offset = 39;
}
else if (ID[0] == 'J' || ID[0] == 'K' || ID[0] == 'L' || ID[0] == 'M' || ID[0] == 'N')
{
offset = 56;
}
else if (ID[0] == 'O')
{
offset = 44;
}
else if (ID[0] == 'P' || ID[0] == 'Q' || ID[0] == 'R' || ID[0] == 'S' || ID[0] == 'T' || ID[0] == 'U' || ID[0] == 'V' || ID[0] == 'Z')
{
offset = 57;
}
else if (ID[0] == 'X' || ID[0] == 'Y')
{
offset = 58;
}
return offset;
}
此外,後續也會補充另一種作法,改以 map 進行查表轉換。
完整程式碼如下:
#include <iostream>
using namespace std;
int ID_Rule(string ID)
{
int offset = 0;
if (ID[0] == 'A' || ID[0] == 'B' || ID[0] == 'C' || ID[0] == 'D' || ID[0] == 'E' || ID[0] == 'F' || ID[0] == 'G' || ID[0] == 'H' || ID[0] == 'W')
{
offset = 55;
}
else if (ID[0] == 'I')
{
offset = 39;
}
else if (ID[0] == 'J' || ID[0] == 'K' || ID[0] == 'L' || ID[0] == 'M' || ID[0] == 'N')
{
offset = 56;
}
else if (ID[0] == 'O')
{
offset = 44;
}
else if (ID[0] == 'P' || ID[0] == 'Q' || ID[0] == 'R' || ID[0] == 'S' || ID[0] == 'T' || ID[0] == 'U' || ID[0] == 'V' || ID[0] == 'Z')
{
offset = 57;
}
else if (ID[0] == 'X' || ID[0] == 'Y')
{
offset = 58;
}
return offset;
}
int main()
{
string ID;
int Total = 0;
int ENASCII = 0;
int offset = 0;
cin >> ID;
offset = ID_Rule(ID);
ENASCII = ((int(ID[0]) - offset) % 10) * 9 + (int(ID[0]) - offset) / 10;
for (int i = 0; i < 8; i++)
{
Total = Total + (int(ID[i + 1]) - 48) * (8 - i);
}
Total = Total + ENASCII + (int(ID[9]) - 48);
if (Total % 10 == 0)
{
cout << "real" << endl;
}
else
{
cout << "fake" << endl;
}
}
/
以下補上改用map的寫法,目前還在適應C++駝峰式命名(Camel Case),跟上面變數命名有些不同,請見諒。
#include <iostream>
#include <string>
#include <map>
using namespace std;
int IdRule(string id)
{
map<char, int> id_map = {
{'A', 10}, {'B', 11}, {'C', 12},
{'D', 13}, {'E', 14}, {'F', 15},
{'G', 16}, {'H', 17},{'I', 34},
{'J', 18}, {'K', 19}, {'L', 20},
{'M', 21}, {'N', 22}, {'O', 35},
{'P', 23},{'Q', 24}, {'R', 25},
{'S', 26}, {'T', 27}, {'U', 28},
{'V', 29}, {'W', 32}, {'X', 30},
{'Y', 31}, {'Z', 33}
};
return id_map[id[0]];
}
int main()
{
string id;
int total = 0;
int char_id = 0;
int convertedValue = 0;
cin >> id;
char_id = IdRule(id);
convertedValue = (char_id % 10) * 9 + (char_id) / 10;
for (int i = 0; i < 8; i++)
{
total = total + (int(id[i + 1]) - 48) * (8 - i);
}
total = total + convertedValue + (int(id[9]) - 48);
if (total % 10 == 0)
{
cout << "real" << endl;
}
else
{
cout << "fake" << endl;
}
}