Repeating Decimals UVA - 202

模擬手算計算小數循環部分,長除法的使用例如3 / 7
3 / 7 = 0 … 3
30 / 7 = 4 … 2
20 / 7 = 2 … 4
40 / 7 = 5 … 5
50 / 7 = 7 … 1
10 / 7 = 1 … 3
30 / 7 = 4 … 2
可以看到,已經出現循環0.(42571)。
每一次的除法時都有被除數和餘數,當除數重複出現時就表示出現循環節。
如果除數出現第二次,例如上例中30出現的時刻,就是第二次循環開始的位置。
所以需要記住每一次的商及除數的位置,除數不夠除的時候,補零。

#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <algorithm>
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
using namespace std;
map<int, int> Pos;//用於計算除數的相應位置
/*
 * 從除數和被除數的關係得到循環小數
 * @param n 除數
 * @param d 被除數
 * @param ans 小數部分
 * @param r 循環部分長度
*/
void solve(int n, const int d, string& ans, int& r)
{
    Pos.clear();
    ans = ".";//初始位置是1,ans.size() = 1
    while (true)
    {
        n *= 10;
        int p = Pos[n];
        if (p == 0) Pos[n] = ans.size();//Pos[n], 表示除數是第幾個的位置
        else
        {   //如果除數再次出現,Pos[n]此時大於0
            r = ans.size() - p;//找到循環節
            if (r > 50) {ans.erase(p+50); ans += "...";}//刪除ans的50位置後字符
            ans.insert(p, "(");
            ans += ")";
            break;
        }

        if (n < d) {ans += '0'; continue;}

        int div = n / d, mod = n % d;
        ans += (char)(div + '0');//添加手算小數
        n = mod;
        if (n == 0) {ans += "(0)"; r = 1;break;}
    }
}

int main()
{
    int a, b;
    while (~scanf("%d%d", &a, &b))
    {
        string ans = ".(0)";
        int r = 1;
        if (a % b) solve(a % b, b, ans, r);
        printf("%d/%d = %d%s\n", a, b, a/b, ans.c_str());
        printf("   %d = number of digits in repeating cycle\n\n", r);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章