題目
題目鏈接:整數轉換成羅馬數字 - 題庫 - 計蒜課
1000ms,65536K
給定一個整數 num,將整數轉換成羅馬數字。
如 1, 2, 3, 4, 5 對應的羅馬數字分別爲I,II,III,IV,V等,更詳細的說明見此 鏈接。輸入格式
第一行輸入一個整數 num(1≤num≤3999)。
輸出格式
輸出 num 對應的羅馬數字。
樣例輸入
123
樣例輸出
CXXIII
分析
知識準備
M D C L X V I 1000 500 100 50 10 5 1 1. 相同的數字連寫、所表示的數等於這些數字相加得到的數、如:Ⅲ=3;
2. 小的數字在大的數字的右邊、所表示的數等於這些數字相加得到的數、 如:Ⅷ=8、Ⅻ=12;
3. 小的數字(限於 I、X 和 C)在大的數字的左邊、所表示的數等於大數減小數得到的數、如:Ⅳ=4、Ⅸ=9;
4. 正常使用時、連寫的數字重複不得超過三次
基本思路
要將一個整數num(1≤num≤3999)轉成羅馬數字,首先我們可以對它進行分解:
進制數 | M | D | C | L | X | V | I |
---|---|---|---|---|---|---|---|
數值 | 1000 | 500 | 100 | 50 | 10 | 5 | 1 |
數值表示 | R0 | R1 | R2 | R3 | R4 | R5 | R6 |
個數 | a0 | a1 | a2 | a3 | a4 | a5 | a6 |
觀察發現
根據上面的分解公式可知:
1. 對於進製爲D(500), L(50), V(5)來說,0≤ai≤1,因爲如果超過1,就會向前進位;
對於M(1000), C(100), X(10), I(1)l來說,0≤ai≤4,因爲如果超過4,就會向前進位;
2. 當一個數某部分需要用到進制相減來表示時,可以相減的兩個進制數距離不會超過2個進制距離。否則,這個數一定可以分成出中間的進制,可以用枚舉去簡單驗證;
3. 被減的進制數一定是I(1), X(10), C(100)
特殊情況處理
特殊情況主要發生在要進行進制相減導致進制數位置的變化,有兩類這樣的問題:
1. 相鄰兩個進制相減,比如 4:IV,允許我記爲“4”問題
2. 相隔1個進制相減,比如 9:IX,記爲“9”問題,這種情況相減的時候需要向前借位,高位需要減1。
有更好的算法,歡迎留言聯繫^_^
實現
我是用c語言實現的(事實上文件保存爲c++)
#include <stdio.h>
int main(int argc, char const *argv[]) {
char RomanSym[7] = {'M', 'D', 'C', 'L', 'X', 'V', 'I'};
int RomanNum[7] = {1000, 500, 100, 50, 10, 5, 1};
int a = 0;
int k[7] = {0};
char output[100]; // 將翻譯成的羅馬數字字符串輸出到output
scanf("%d", &a);
for (int i = 0; i < 7; i++) {
k[i] = a / RomanNum[i];
a -= k[i] * RomanNum[i];
}
a = 0; // 重新利用a,作爲數組下標
for (int i = 6; i >= 0; i--) {
// 逆序
if (k[i] == 4 && k[i-1] == 0) {
// "4"問題
output[a++] = RomanSym[i-1];
output[a++] = RomanSym[i];
} else if (k[i] == 4 && k[i-1] == 1) {
// "9"問題
k[i-1]--; // 向前借位需要減1
output[a++] = RomanSym[i-2];
output[a++] = RomanSym[i];
} else {
// 其他情況循環輸出即可
for (int j = 0; j < k[i]; j++) {
output[a++] = RomanSym[i];
}
}
}
// 逆序輸出
for (int i = a - 1; i >= 0; i--) {
putchar(output[i]);
}
putchar('\n');
return 0;
}