蓝桥杯:十二进制转八进制
题目要求将输入n个十六进制字符出串转为八进制输出对输入十六进制数长度要求小于等于100000(输出忽略前导0)
因为输入数长度过大基本排除使用int,long,long long进行存储。
所以有基本思想用数组存放输入的16进制数后一位16进制转换为四位2进制,如果将所有位全转为2进制那么长度会变为40000位,结果是显然不理想的。由三位二进制对应一位八进制我们可以取三和四的最小公倍数12,每将三位十六进制数转为十二位二进制数就将其转换为三位八进制数,进行输出或者保存至另一字符组。
十六进制转二进制时若对每位进行除二取余,一位数必然要进行多次运算,而一位十六进制转二进制只有16种情况可以用switch语句选择转换,同理八进制也可以,所以有了初始程序:
#include<stdio.h>
#include<string.h>
int main()
{
int n,i,j,k,a=0,cur,st,ok;
char s[10][100000],z[12];
scanf("%d",&n);
for(j=0;j<n;j++)
scanf("%s",s[j]);
for(j=0;j<n;j++)
{
ok=1;
for(i=0;i<strlen(s[j]);i++)
{
if(strlen(s[j])%3!=0&&a==0&&(a=(3-(strlen(s[j])%3)))!=0)
{
for(k=0;k<a*4;k++)
z[k]='0';
}
switch(s[j][i])
{
case '0':z[k]='0';z[k+1]='0';z[k+2]='0';z[k+3]='0';break;
case '1':z[k]='0';z[k+1]='0';z[k+2]='0';z[k+3]='1';break;
case '2':z[k]='0';z[k+1]='0';z[k+2]='1';z[k+3]='0';break;
case '3':z[k]='0';z[k+1]='0';z[k+2]='1';z[k+3]='1';break;
case '4':z[k]='0';z[k+1]='1';z[k+2]='0';z[k+3]='0';break;
case '5':z[k]='0';z[k+1]='1';z[k+2]='0';z[k+3]='1';break;
case '6':z[k]='0';z[k+1]='1';z[k+2]='1';z[k+3]='0';break;
case '7':z[k]='0';z[k+1]='1';z[k+2]='1';z[k+3]='1';break;
case '8':z[k]='1';z[k+1]='0';z[k+2]='0';z[k+3]='0';break;
case '9':z[k]='1';z[k+1]='0';z[k+2]='0';z[k+3]='1';break;
case 'A':z[k]='1';z[k+1]='0';z[k+2]='1';z[k+3]='0';break;
case 'B':z[k]='1';z[k+1]='0';z[k+2]='1';z[k+3]='1';break;
case 'C':z[k]='1';z[k+1]='1';z[k+2]='0';z[k+3]='0';break;
case 'D':z[k]='1';z[k+1]='1';z[k+2]='0';z[k+3]='1';break;
case 'E':z[k]='1';z[k+1]='1';z[k+2]='1';z[k+3]='0';break;
case 'F':z[k]='1';z[k+1]='1';z[k+2]='1';z[k+3]='1';break;
}
k+=4;
if(k==12)
{
for(cur=0;cur<12;cur+=3)
if(z[cur]=='0'&&z[cur+1]=='0'&&z[cur+2]=='0')if(ok);else putchar('0');
else if(z[cur]=='0'&&z[cur+1]=='0'&&z[cur+2]=='1'){putchar('1');ok=0;}
else if(z[cur]=='0'&&z[cur+1]=='1'&&z[cur+2]=='0'){putchar('2');ok=0;}
else if(z[cur]=='0'&&z[cur+1]=='1'&&z[cur+2]=='1'){putchar('3');ok=0;}
else if(z[cur]=='1'&&z[cur+1]=='0'&&z[cur+2]=='0'){putchar('4');ok=0;}
else if(z[cur]=='1'&&z[cur+1]=='0'&&z[cur+2]=='1'){putchar('5');ok=0;}
else if(z[cur]=='1'&&z[cur+1]=='1'&&z[cur+2]=='0'){putchar('6');ok=0;}
else if(z[cur]=='1'&&z[cur+1]=='1'&&z[cur+2]=='1'){putchar('7');ok=0;}
k=0;
}
}
a=0;
putchar('\n');
}
return 0;
}
很明显从结构上看就十分复杂(代码长度2100kb),提交结果超时!!
很明显程序进行太多次判断,再看十六进制转二进制有以下对应:
0=》0000 1=》00012=》0010.。。。。。。15=》1111
若建立字符组存放十六进制数对应的二进制数则十六进制数刚好为数组下标:比如a[0]="0000",a[1]="0001";这样就不必进行判断直接使用十六进制数读取对应的二进制数。
而二进制数转八进制数则可以这样解决:eg: 111 1x2^2+1x2^1+1x2^0=7
注意在转换时建立一长度为13的字符组保存二进制数方便读取。
则可以有以下程序:
(注意:字符间的运算会使用字符的ASCII代码进行加减乘除而‘0’的代码为48减去48刚好为0,A~F的代码减7刚好比9的代码大一再减48其代码刚好为0;程序中多次使用代码加减!!)
#include<stdio.h>
#include<string.h>
int main()
{
int n,i,j,k,a,cur,ok,m,l;
char s[10][100001],d16[16][5]={"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"},out[140000]={},z[13]={};
scanf("%d",&n);
for(j=0;j<n;j++)
scanf("%s",s[j]);
for(j=0;j<n;j++)
{
k=0;ok=1;m=0; /*初始化标记数据*/
l=strlen(s[j]); /* 初始化标记数据*/
a=3-l%3; /*初始化标记数据*/
if(a==3) ok=0; /*十六进制数长度刚好为3的倍数时转二进制不需补0,ok标记其是否为3的倍数0是1不是*/
for(i=0;i<l;i++) /*逐位读取十六进制数进行转换*/
{
if(65<=s[j][i])
s[j][i]-=7;
if(ok) /*十六进制数位数不足转二进制时补0占位*/
if(a==1){
strcat(z,"0000");k=k+4;ok=0;
}else if(a==2){
strcat(z,"00000000");k=k+8;ok=0;
}
z[k++]=d16[s[j][i]-48][0]; /*一位十六进制转四位二进制*/
z[k++]=d16[s[j][i]-48][1];
z[k++]=d16[s[j][i]-48][2];
z[k++]=d16[s[j][i]-48][3];
if(k==12) /*每转三位十六进制数将其转为四位八进制数*/
{
for(cur=0;cur<12;m++)
out[m]=((z[cur++]-48)*4+(z[cur++]-48)*2+(z[cur++]-48)*1)+48;
z[0]='\0';k=0; /*z[0]='\0'初始化字符串结束符位置避免溢出*/
}
}
for(;k<3;k++) /*输出时忽略前导0*/
if(out[k]!=48) break;
for(;k<m;k++)
printf("%c",out[k]);
putchar('\n');
}
return 0;
}
再次提交正确:
代码长度:971B cpu使用:15ms
本代码争对题目,若有不足欢迎补充