《算法笔记》学习日记——3.5 进制转换

3.5 进制转换

Codeup Contest ID:100000579

问题 A: 又一版 A+B

题目描述
输入两个不超过整型定义的非负10进制整数A和B(<=231-1),输出A+B的m (1 < m <10)进制数。
输入
输入格式:测试输入包含若干测试用例。每个测试用例占一行,给出m和A,B的值。
当m为0时输入结束。
输出
输出格式:每个测试用例的输出占一行,输出A+B的m进制数。
样例输入

2 4 5
8 123 456
0

样例输出

1001
1103

提示
注意输入的两个数相加后的结果可能会超过int和long的范围。
思路
首先,十进制转M进制肯定是除M取余,然后倒序输出(先算出来的余数存在低位,后算出来的余数存在高位)。于是我的思路是开一个int型数组,然后从下标0开始存放余数,并记录长度,最后倒序输出即可。
此外,提示中也说到了两数相加可能会超int型的范围,那么此时只要把a、b都定义成long long就可以了(用double的话记得要用fmod函数floor向下取整函数)。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int main(){
	int m;
	long long a, b;
	while(scanf("%d%d%d", &m, &a, &b) != EOF){
		long long y = a+b;
		if(m==0) break;
		int x[1000];
		int len = 0;
		for(int i=0;;i++){
			if(y/m==0){
				x[i] = y%m;
				len++;
				break;
			}
			else{
				x[i] = y%m;
				len++;
				y = y/m;
			}
		}
		for(int i=len-1;i>=0;i--) printf("%d", x[i]);
		printf("\n");
	} 
	return 0;
}

问题 B: 数制转换

题目描述
求任意两个不同进制非负整数的转换(2进制~16进制),所给整数在long所能表达的范围之内。
不同进制的表示符号为(0,1,…,9,a,b,…,f)或者(0,1,…,9,A,B,…,F)。
输入
输入只有一行,包含三个整数a,n,b。a表示其后的n 是a进制整数,b表示欲将a进制整数n转换成b进制整数。a,b是十进制整数,2 =< a,b <= 16。
输出
可能有多组测试数据,对于每组数据,输出包含一行,该行有一个整数为转换后的b进制数。输出时字母符号全部用大写表示,即(0,1,…,9,A,B,…,F)。
样例输入

4 123 10

样例输出

27

提示
用字符串存储和表示不同进制的数。
思路
首先,肯定是用字符串把输入的数存进来(提示也说了),然后先把a进制数转换成10进制数,再将10进制数转换成b进制数输出即可。然后字符串和整型之间的转换,只要减去或者加上相差的ascii码值即可。
要注意的是,这里的n应该是字符串,因为可以带符号(比如16进制的ff)。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int main(){
	int a, b;
	char temp[1000];
	while(scanf("%d %s %d", &a, temp, &b) != EOF){
		int len = strlen(temp);//这里的len是n的位数(a进制) 
		int n_ten =  0;
		for(int i=0, j=len-1;i<len, j>=0;i++, j--){
			if(temp[i]>='0'&&temp[i]<='9') n_ten += pow(a,j)*((int)temp[i]-48);
			if(temp[i]>='a'&&temp[i]<='z') n_ten += pow(a,j)*((int)temp[i]-87);
			if(temp[i]>='A'&&temp[i]<='Z') n_ten += pow(a,j)*((int)temp[i]-55);
		}
		char tmp[1000];
		int x[1000];
		int len2 = 0; //这里的len2记录的是十进制数的位数 
		for(int i=0;;i++){
			if(n_ten/b==0){
				x[i] = n_ten%b;
				len2++;
				break;
			}
			else{
				x[i] = n_ten%b;
				len2++;
				n_ten = n_ten/b;
			}
		}
		for(int i=0;i<len2;i++){
			if(x[i]>=0&&x[i]<=9) tmp[i] = x[i] + '0';
			else{
				if(x[i]==10) tmp[i] = 'A';
				if(x[i]==11) tmp[i] = 'B';
				if(x[i]==12) tmp[i] = 'C';
				if(x[i]==13) tmp[i] = 'D';
				if(x[i]==14) tmp[i] = 'E';
				if(x[i]==15) tmp[i] = 'F';
			}
		}
		for(int i=len2-1;i>=0;i--) printf("%c", tmp[i]);
		printf("\n");
		memset(temp, 0, sizeof(temp));
		memset(tmp, 0, sizeof(tmp));
		memset(x, 0, sizeof(x));
	} 
	return 0;
}

问题 C: 进制转换

题目描述
将一个长度最多为30位数字的十进制非负整数转换为二进制数输出。
输入
多组数据,每行为一个长度不超过30位的十进制非负整数。
(注意是10进制数字的个数可能有30个,而非30bits的整数)
输出
每行输出对应的二进制数。
样例输入

985
211
1126

样例输出

1111011001
11010011
10001100110

思路
这一题看上去跟问题A差不多,只不过问题A是十进制数到别的进制,这题是十进制到二进制。
但是,这题有两个问题:①不能用int型,因为数据范围不够,最多只有9位;②不能用long long,因为long long也就18位;③double型也不行,因为虽然取值范围很大,而且有ceil向下取整函数和fmod取余函数,但是实际精度不够(15~16位)。所以,这题最合适的解法是用字符串处理:把输入的数据存储到字符串,然后对每一位进行除2的操作(比如985/2,我们要是列竖式的话,其实是9/2,得4,余1再给8,18/2,得9,5/2,得2余1,至此,一次才算完,得492余1,因为30位长度的数字实在是太大了,根本无法直接进行除法或者取整操作),一直往复循环,直到商为0为止。

但是我的代码有个很神奇的地方,如果提交语言选择C++会判答案错误0%,如果选择C就会正确100%……我也不知道是什么原因……
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int main(){
	char str1[100];
	char str2[100];
	int x[100];
	while(scanf("%s", str1) != EOF){
		char judge[100];
		for(int i=0;i<strlen(str1);i++) judge[i] = '0';
		//生成一个只含0但是长度和str1相等的空串作为参考 
		int len = 0;
		while(1){
			int temp = 0;
			if(strcmp(str2, judge)==0) break; 
			for(int i=0;i<strlen(str1);i++){
				temp = temp*10+str1[i]-'0';
				str2[i] = temp/2 + '0';
				if(temp%2==1) temp = 1;
				else temp = 0; 
			}
			x[len] = temp;
			len++;
			strcpy(str1, str2);
		}
		for(int i=len-1;i>=0;i--) printf("%d", x[i]);
		printf("\n");
		memset(str1, 0, sizeof(str1));
		memset(str2, 0, sizeof(str2));
		memset(x, 0, sizeof(x));
		memset(judge, 0, sizeof(judge));
	} 
	return 0;
}

问题 D: 八进制

题目描述
输入一个整数,将其转换成八进制数输出。
输入
输入包括一个整数N(0<=N<=100000)。
输出
可能有多组测试数据,对于每组数据,
输出N的八进制表示数。
样例输入

9
8
5

样例输出

11
10
5

思路
这题才是真的跟问题A类似,把问题A中的m换成8就行了。
代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int main(){
	int n;
	int x[100];
	while(scanf("%d", &n) != EOF){
		int len = 0;
		for(int i=0;;i++){
			if(n/8==0){
				x[i] = n%8;
				len++;
				break;
			}
			else{
				x[i] = n%8;
				len++;
				n = n/8;
			}
		}
		for(int i=len-1;i>=0;i--) printf("%d", x[i]);
		printf("\n");
	} 
	return 0;
}

小结

总的来说,进制转换这一类的题目难度也不算太大,稍微有点难度的就是问题C,因为给的数据范围太大了(30位),所以必须考虑用字符串进行一位一位的除法操作,否则只要是范围小于long long的话,直接操作还是蛮快的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值