【程式設計訓練】計算校驗碼

2020-08-12 16:28:59

個人思路僅供參考,如有不足歡迎交流。

【問題描述】

傳送一個B(B≤16)進位制的數值N時,最後加上一個一位(B進位制的)校驗碼,使得N加上校驗位後能被B-1整除。比如十進制的數值12310,其校驗碼就是3,因爲十進制數值123310能被9整除。16進位制的數7816,其校驗碼爲0,因爲16進位制的78016是15的倍數。超過十進制後,用字母a表示10,字母b表示11,字母c表示12,字母d表示13,字母e表示14,字母f表示15。

告訴你進位制B,以及一個B進位制的正整數N,要求你計算正整數N在B進位制下的校驗碼。

【輸入形式】

輸入第一行正整數t (10 ≤ n ≤ 100),表示有多少組測試數據。

後面有t行,每行兩個正整數B,N(2≤ B≤16),中間用一個空格隔開,B是10進位制整數,N用B進位制形式表示。測試數據保證沒有非法的B進位制數N(也即N中每一位都是在0到B-1之間,沒有前導0)。

40%的測試數據N的位數L 1 ≤ L≤ 10;

30%的測試數據N的位數L 1 ≤ L≤ 10^2;

20%的測試數據N的位數L 1 ≤ L≤ 10^3;

10%的測試數據N的位數L 1 ≤ L≤ 10^4;

【輸出形式】

對於每組測試數據,輸出一位佔一行:正整數N在B進位制下的校驗碼。(如果校驗碼可以爲B-1,也可以爲0,輸出0)。

【樣例輸入】

4
10 123
16 78
16 1234321
12 ab

【樣例輸出】

3
0
e
1

【樣例說明】

第一行的4表示有4組測試數據,下面 下麪四行,每行一組測試數據。

第一組測試數據 10進位制數123 最後新增檢驗碼3,10進位制數1233是9(=10-1)的倍數

第二組測試數據 16進位制數78 最後新增檢驗碼0,16進位制數780是15(=16-1)的倍數

第三組測試數據 16進位制數1234321 最後新增檢驗碼e(=14),16進位制數1234321e是15(=16-1)的倍數

第四組測試數據 12進位制數ab 最後新增檢驗碼1,12進位制數ab1是11(12-1)的倍數

【Tips】

B進位制的數能被B-1整除,當且僅當各位數位和能被B-1整除。

第一組測試數據 10進位制數123 最後新增檢驗碼3,10進位制數1233各位數位和是9,是9的倍數

第二組測試數據 16進位制數78 最後新增檢驗碼0,16進位制數780各位數位和是15,是15的倍數

第三組測試數據 16進位制數1234321 最後新增檢驗碼e,16進位制數1234321e各位數位和是30,是15的倍數

第四組測試數據 12進位制數ab 最後新增檢驗碼1,12進位制數ab1各位數位和是22,是11的倍數

【思路和做法】

由於很多數據中數的長度明顯過長,所以採用了從頭到尾類似於豎式除法的方式來計算,類似於另一題「A除以B」
提交程式碼如下(10/10分,C++):

//37.校驗碼
#include <iostream>
#include <string>

using namespace std;

bool check(string _num, int base)
{
    int len = _num.length();      //加上校驗碼之後數的位數
    int temp = 0, t_num = 0;      //每次除法的被除數、當前位置的數位(t_num和r賦值爲0是爲了消除警告)
    int r = 0;                    //最後的餘數
    for (int i = 0; i < len; i++) //從高位開始,類似於用豎式做除法
    {
        switch (_num[i]) //爲當前位置數位賦值
        {
        case '0':
        {
            t_num = 0;
            break;
        }
        case '1':
        {
            t_num = 1;
            break;
        }
        case '2':
        {
            t_num = 2;
            break;
        }
        case '3':
        {
            t_num = 3;
            break;
        }
        case '4':
        {
            t_num = 4;
            break;
        }
        case '5':
        {
            t_num = 5;
            break;
        }
        case '6':
        {
            t_num = 6;
            break;
        }
        case '7':
        {
            t_num = 7;
            break;
        }
        case '8':
        {
            t_num = 8;
            break;
        }
        case '9':
        {
            t_num = 9;
            break;
        }
        case 'a':
        {
            t_num = 10;
            break;
        }
        case 'b':
        {
            t_num = 11;
            break;
        }
        case 'c':
        {
            t_num = 12;
            break;
        }
        case 'd':
        {
            t_num = 13;
            break;
        }
        case 'e':
        {
            t_num = 14;
            break;
        }
        case 'f':
        {
            t_num = 15;
            break;
        }

        default:
            break;
        }
        temp = t_num + temp * base; //temp=本位數位+上一位數位*base

        if (temp < base && i == 0) //_num的第一位<base,
            continue;
        else
        {
            r = temp % (base - 1); //餘數
            temp = r;              //本次計算的餘數繼承到下一次計算
        }
    }
    if (r == 0) //最後餘數爲0,即能夠整除
    {
        cout << _num[len - 1] << endl; //輸出校驗碼
        return true;                   //找到校驗碼
    }
    return false; //沒有找到校驗碼
}

int main()
{
    int n;            //測試數據有n組
    int base;         //base進位制
    string num, _num; //輸入的數、加上校驗碼之後的數
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> base >> num;
        for (int j = 0; j < base; j++) //校驗碼j從0到base-1
        {
            switch (j)
            {
            case 0:
            {
                _num = num + '0';
                break;
            }
            case 1:
            {
                _num = num + '1';
                break;
            }
            case 2:
            {
                _num = num + '2';
                break;
            }
            case 3:
            {
                _num = num + '3';
                break;
            }
            case 4:
            {
                _num = num + '4';
                break;
            }
            case 5:
            {
                _num = num + '5';
                break;
            }
            case 6:
            {
                _num = num + '6';
                break;
            }
            case 7:
            {
                _num = num + '7';
                break;
            }
            case 8:
            {
                _num = num + '8';
                break;
            }
            case 9:
            {
                _num = num + '9';
                break;
            }
            case 10:
            {
                _num = num + 'a';
                break;
            }
            case 11:
            {
                _num = num + 'b';
                break;
            }
            case 12:
            {
                _num = num + 'c';
                break;
            }
            case 13:
            {
                _num = num + 'd';
                break;
            }
            case 14:
            {
                _num = num + 'e';
                break;
            }
            case 15:
            {
                _num = num + 'f';
                break;
            }
            default:
                break;
            }
            if (check(_num, base) == true) //獲取到校驗碼
            {
                break;
            }
        }
    }
    return 0;
}