計蒜課:整數轉換成羅馬數字

題目

題目鏈接:整數轉換成羅馬數字 - 題庫 - 計蒜課

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

num=aiRii=06
其中
ai=(numajRj)/Rij=0i1
上式的除法爲整數整除。這裏的分解是從大進制到小進制分解。一般情況下,按第1,2條規則,ai爲多少,對應的羅馬字符就有多少個;但由於第3,4條規則的限制,所以我們還需要對ai進行修正以及進制數位置進行修正

觀察發現

根據上面的分解公式可知:
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章