OpenJudge NOI 1.13 44:正整数的任意进制转换

【题目链接】

OpenJudge NOI 1.13 44:正整数的任意进制转换
注意:题目说是正整数的进制转换,而实际上输入的数字可能有0。

【题目考点】

1. 数制
2. 高精度

【解题思路】

先处理字符串,将输入的字符串拆分成p,p进制字符串n,及q。

遍历字符串,遇到逗号时,截取一段字符串。将截取出的第一和第三段字符串转为整数,就是p与q,第二段字符串为数字串。

先考虑如果涉及的都是低精度数字,应该如何将p进制的n转为q进制。
先将p进制的n转为值v,再对v在q进制下做数字拆分,得到q进制下的数字串。

#include<bits/stdc++.h>
using namespace std;
int p, q;
string n; 
void parse(string s)//解析输入的字符串s 
{
    string t;
    int c = 0;//记录上个逗号的位置 
    for(int i = 0; i < s.length(); ++i)
    {
        if(s[i] == ',')
        {
            if(c == 0)//如果是第一个逗号
            {
                t = s.substr(0, i);//从0开始取i个
                p = stoi(t);//这个子串为第一个进制数字      
                c = i;
            }
            else//如果是第二个逗号 
            {
                n = s.substr(c+1, i-c-1);//c是上一个逗号的位置,数字串第一个字符的位置为c+1,此时第二个逗号位置为i,数字串长度为i-c-1 
                t = s.substr(i+1);//从i+1到末尾为第二个进制数字
                q = stoi(t);
                break; 
            }
        }
    }
}
int getVal(char c)//字符转数值 
{
    if(c >= '0' && c <= '9')
        return c-'0';
    else
        return c-'A'+10;
}
char getCh(int n)//数值转字符 
{
    if(n >= 10)
        return n-10+'A';
    else
        return n+'0';
}
int toVal(string n)
{
    int num = 0;
    for(int i = 0; i < n.length(); ++i)
        num = num*p + getVal(n[i]);
    return num;
}
string toStr(int v)
{
    string r;
    int a = v;
    do//q进制下的数字拆分 
    {
        r = getCh(a%q) + r;   
        a /= q;
    }while(a > 0);
    return r;
}
int main()
{
    string s;
    cin >> s;
    parse(s);
    int v = toVal(n);
    cout << toStr(v);
    return 0;
}

以上代码可以解决数值在int类型范围内的数字的数制转换。
而本题n可以达到50位,必须用高精度数字表示。
将输入的数字串转为p进制高精度数字。
上述代码中“将p进制数字转为值”这一步不用做了,因为不存在可以表示这个值的基本数据类型。
直接将p进制高精度数字,转为q进制高精度数字,其逻辑与toStr函数的逻辑是相同的。
先让高精度数字a的值为p进制高精度数字n的值。只要a不为0,每次让a除以q(高精除低精),得到余数r(低精度)作为q进制数字串的一位,将得到的商再赋值给a。循环执行,直到a为0。这样就得到了q进制字符串。
注意:数位分离写法for(int a = n; a > 0; a /= 10)只能在n大于0时才能使用。当n可能等于0时,要用do...while的写法。这里的高精度数字n仍然可能是等于0的(虽然题目说了“正整数”,但实际数据中存在0)
考虑极端情况如果36进制数字“50位Z”转为二进制数字,得到的数字位数可以达到300位。

【题解代码】

解法1:使用数字数组
#include<bits/stdc++.h>
using namespace std;
#define N 55
int p, q;
string n;
void parse(string s)//解析字符串s 
{
	int c1 = 0, c2 = 0;
	for(int i = 0; i < s.length(); ++i)
	{
		if(s[i] == ',')
		{
			if(c1 == 0)
				c1 = i;
			else
				c2 = i;
		}
	}
	p = stoi(s.substr(0, c1));
	n = s.substr(c1+1, c2-c1-1);
	q = stoi(s.substr(c2+1));
}
char getCh(int a)
{
	if(a < 10)
		return a + '0';
	else
		return a - 10 + 'A';
}
int getVal(char c)
{
	if(c >= '0' && c <= '9')
		return c - '0';
	else
		return c - 'A' + 10;
}
void numcpy(int a[], int b[])
{
	for(int i = 0; i <= b[0]; ++i)
		a[i] = b[i];
}
void toNum(int a[], string s)
{
	a[0] = s.length();
	for(int i = 1; i <= a[0]; ++i)
		a[i] = getVal(s[a[0] - i]);
}
void setLen(int a[], int i)
{
	while(a[i] == 0 && i > 1)
		i--;
	a[0] = i;
}
int Divide(int a[], int b, int k)//a /= b,a是k进制数字,返回a % b的值。 
{
	int temp;
	int m = 0;
	for(int i = a[0]; i >= 1; --i)
	{
		temp = (m * k + a[i]) / b;
		m = (m * k + a[i]) % b;
		a[i] = temp;
	}
	setLen(a, a[0]);
	return m;
}
void showNum(int a[])
{
	for(int i = a[0]; i >= 1; --i)
		cout << a[i] << ' ';
	cout << endl;
}
string getStr(int n[])//n:高精 
{
	string s;
	int a[N] = {};
	numcpy(a, n);
	do//高精除低精 a /= q
	{
		s = getCh(Divide(a, q, p)) + s;
	}while(!(a[0] == 1 && a[1] == 0));//a != 0
	return s;
}
int main()
{
	string s;
	int m, a[N] = {};
	cin >> m;
	while(m--)
	{
		cin >> s;
		parse(s);
		toNum(a, n);
		cout << getStr(a) << endl;
	} 
	return 0;
}
解法2:高精度数字类
#include<bits/stdc++.h>
using namespace std;
#define N 305 //注意数字36进制数字50位Z转换为二进制后最多可以达到300位
struct HPN
{
    int a[N], k;//a:数字数组 k:进制 
    HPN(){}
    HPN(string s, int _k)
    {
        a[0] = s.length();
        for(int i = 1; i <= s.length(); ++i)
            a[i] = getVal(s[s.length()-i]);
        k = _k;
    }
    int getVal(char c)//字符转数值 
    {
        return isdigit(c) ? c - '0' : c - 'A' + 10;
    }
    char getCh(int n)//数值转字符 
    {
        return n >= 10 ? n - 10 + 'A' : n + '0'; 
    }
    int& operator [] (int i)
    {
        return a[i];
    }
    void operator /= (int b)//a /= b 高精除低精 
    {
        int m = 0, d;//m:中间临时使用的数字,是上一次小规模除法的余数,也是下一次的被除数 
        for(int i = a[0]; i >= 1; --i)
        {
            d = m * k + a[i];//临时被除数 
            m = d % b;
            a[i] = d / b;
        }
        int l = a[0];
        while(a[l] == 0 && l > 1)
            l--;
        a[0] = l;
    }
    int operator % (int b)//a%b 高精模低精 
    {
        int m = 0;//m:中间临时使用的数字,是上一次小规模除法的余数,也是下一次的被除数 
        for(int i = a[0]; i >= 1; --i)
            m = (m * k + a[i]) % b;
        return m;
    }
    void changeSys(int x)//将当前数字的进制从k改为x 
    {
        HPN t = *this;//t先设为与自己相同
        k = x;
        int c, ai = 0;
        do
        {
            a[++ai] = t % x;//高精模低精:t%x的结果填充到自己的数字数组a中 
            t /= x;//高精除低精 
        }while(!(t[0] == 1 && t[1] == 0));//只要高精度数字t不是0 
        a[0] = ai;
    }
    void show()
    {
        for(int i = a[0]; i >= 1; --i)
            cout << getCh(a[i]);
        cout << endl;
    }
};
void parse(string s, string &n, int &p, int &q)//解析输入的字符串s,得到p,q,n 
{
    int c1 = 0, c2 = 0;//c1, c2:第1、第2逗号的位置 
    for(int i = 0; i < s.length(); ++i)
    {
        if(s[i] == ',')
        {
            if(c1 == 0)
                c1 = i;
            else
                c2 = i;
        }
    }
    p = stoi(s.substr(0, c1));
    q = stoi(s.substr(c2+1));
    n = s.substr(c1+1, c2-c1-1);
}
int main()
{
    HPN num;
    int p, q, t;
    string s, n;
    cin >> t;
    while(t--)
    {
        cin >> s;
        parse(s, n, p, q);
        num = HPN(n, p);//p进制高精度数字num
        num.changeSys(q);
        num.show();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值