1044 火星数字 ——c实现

1044 火星数字 (20 分)

火星人是以 13 进制计数的:

  • 地球人的 0 被火星人称为 tret。
  • 地球人数字 1 到 12 的火星文分别为:jan, feb, mar, apr, may, jun, jly, aug, sep, oct, nov, dec。
  • 火星人将进位以后的 12 个高位数字分别称为:tam, hel, maa, huh, tou, kes, hei, elo, syy, lok, mer, jou。

例如地球人的数字 29 翻译成火星文就是 hel mar;而火星文 elo nov 对应地球数字 115。为了方便交流,请你编写程序实现地球和火星数字之间的互译。

输入格式:

输入第一行给出一个正整数 N(<100),随后 N 行,每行给出一个 [0, 169) 区间内的数字 —— 或者是地球文,或者是火星文。

输出格式:

对应输入的每一行,在一行中输出翻译后的另一种语言的数字。

输入样例:

4
29
5
elo nov
tam

输出样例:

hel mar
may
115
13

思路:

这道题和多数进制转换的题目看起来很相似。存在的难点是如果输入的是火星文,可能会是一个两个字符串,因此字符串的分割是难点。所以这道题的难点一是判断输入的是地球数字还是火星文,第二步是分割火星文字符,其三才是两者之间的转化。

1 判断输入的语言

由于火星文是字符串,地球文是数字,因此看起来比较容易判断。但是注意,由于火星文的字符串之间有空格,所以有必要一次将整行全部读完。这里需要用到fgets()。

fgets

从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize-1个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过bufsize-1,则fgets只返回一个不完整的行,但是,缓冲区总是以NULL字符结尾,对fgets的下一次调用会继续读该行。函数成功将返回buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror函数来判断。fgets()在头文件

fgets()的典型用法如下:

fgets(buffer,n,stdin)

功能是从标准输入设备键盘(也就是stdin:stdandard input)读入n-1个字符串。由于字符串结尾以"\0"结束,因此必须留出一个,也就是只能读入n-1个。buffer可是是提前定义好的数组的指针,也就是数组名。

用这种方法可以一次将一行输入全部读入buffer缓存。但是还没有进行赋值,因此下面还要将读入的信息用于赋值和判断。更准确地说,是进行判断和赋值,因此只有先判断清楚输入的是火星文还是地球文,才能决定下面怎么赋值。比如,这里先判断读到的是不是数字,可以用中的isdigit()函数来进行判断,如果读到的是数字,就要进行赋值,然后从数字转换到火星文。如果读到的是火星文,也要转换到地球文。

注意,这里赋值不能再用scanf()函数,因为scanf会读入下一个输入,而非目前读进到buffer中的输入。这里需要用到能将已经读入缓存的数据进行赋值操作,这个函数是sscanf()。百度介绍如下:

sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。sscanf()在头文件

例如:

sscanf("1 2 3","%d %d %d",buf1, buf2, buf3); 成功调用返回值为3,即buf1,buf2,buf3均成功转换。

sscanf("1 2","%d %d %d",buf1, buf2, buf3); 成功调用返回值为2,即只有buf1,buf2成功转换。

(注意:此处buf均为地址)

 

      1、一般用法

1

2

3

char buf[512] = ;

sscanf("123456 ""%s", buf);

printf("%s\n", buf);

结果为:123456
  2. 取指定长度的字符串。如在下例中,取最大长度为4字节的字符串。

1

2

sscanf("123456 ""%4s", buf);

printf("%s\n", buf);

结果为:1234
  3. 取到指定字符为止的字符串。如在下例中,取遇到空格为止字符串。

1

2

sscanf("123456 abcdedf""%[^ ]", buf);

printf("%s\n", buf);

结果为:123456
  4. 取仅包含指定字符集的字符串。如在下例中,取仅包含1到9和小写字母的字符串。

1

2

sscanf("123456abcdedfBCDEF""%[1-9a-z]", buf);

printf("%s\n", buf);

结果为:123456abcdedf
  5. 取到指定字符集为止的字符串。如在下例中,取遇到大写字母为止的字符串。

1

2

sscanf("123456abcdedfBCDEF""%[^A-Z]", buf);

printf("%s\n", buf);

结果为:123456abcdedf
  6、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中

1

2

sscanf("iios/12DDWDFF@122""%*[^/]/%[^@]", buf);

printf("%s\n", buf);

结果为:12DDWDFF
  7、给定一个字符串"hello, world",仅保留"world"。(注意:“,”之后有一空格)

1

2

sscanf("hello, world""%*s%s", buf);

printf("%s\n", buf);

结果为:world
  P.S. %*s表示第一个匹配到的%s被过滤掉,即hello被过滤了,
  如果没有空格则结果为NULL。 [2] 

补充知识:

%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)

%[aB'] 匹配a、B、'中一员,贪婪性

%[^a] 匹配非a的任意字符,并且停止读入,贪婪性

这样就可以完整的读入一行信息并准确的进行赋值操作。

2 分割火星文字符

由于地球文只是数字无需转化。火星文之间有空格,因此注意要将火星文断开。这里要用到strtok()函数。百度介绍如下:

strtok

分解字符串为一组字符串。s为要分解的字符,delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)。首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。strtok()在头文件

原型    char *strtok(char s[], const char *delim);

功能

分解字符串为一组字符串。s为要分解的字符串,delim为分隔符字符串。

例如:strtok("abc,def,ghi",","),最后可以分割成为abc def ghi.尤其在点分十进制的IP中提取应用较多。

常用功能是这样的:

第一次可以将s的指针传进去,第二次就需要将指针置为NULL。所以常用写法如下:

str1=strtok(line," \n");
str2=strtok(line," \n");

实例:

#include 
#include 
int main(void)
{
    char input[16]="abc,d";
    char*p;
    /*strtok places a NULL terminator
    in front of the token,if found*/
    p=strtok(input,",");
    if(p)
        printf("%s\n",p);
        /*A second call to strtok using a NULL
        as the first parameter returns a pointer
        to the character following the token*/
    p=strtok(NULL,",");
    if(p)
        printf("%s\n",p);
    return 0;
}

输出为:

abc

d

利用上述实例中的方法就可以断开输入的火星文字符串。由于火星文可能只有一个字符串,比如整20——hel。因此建议写成如下格式:

strtok(line," \n");
strtok(NULL," \n");

2018.12.07

也可以完全没必要这么麻烦。因为输入的数字是[0,169),因此用火星文表示不会是三个单词,这就为如何断句提供了方便。因为高位都是三个字母的,低位有3个和4个字母的。所以如果不是数字,直接判断长度就可以啦。

注意事项:

1、注意火星文的13只是一个tam,26只是一个hel。所以如果是两个位的话,要根据%13之后的余数是否为0,判断转换为火星文之后是有两个单词,还是一个单词。

2、只要在读入N之后用一个getchar()就好。for循环中不需要用getchar(),否则会出现错误。

这种思路也比较简单,见代码2.

 

3 火星文与地球文之间的转化

地球文转到火星文比较简单,取出对应的高低位,在数组中查找即可。由于有了前两步的基础,火星文转地球文也比较简单,只需要将截断之后的火星文在建立的火星文字符串数组中遍历即可,在乘以对应的进制。

完整代码:

代码1

//1044 火星数字 V1
#include 
#include 
#include 

char *units[]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"};
char *tens[]={"tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};

int Mars2Earth(char *s){
	if(s){
		int i;
		for(i=0;i<13;i++){
			if(strcmp(s,units[i])==0)	return i;	//个位数字 
		}
		for(i=1;i<13;i++){
			if(strcmp(s,tens[i-1])==0)		return i*13;	//高位数字 
		}
	}
	return 0;
}

int main(){
	int n,m,i;	
	char line[11];
	fgets(line,11,stdin);
	sscanf(line,"%d",&n);
	for(i=0;i

代码2

#include 
#include 
#include 
using namespace std;
int main(){
	int n;	cin>>n;
	string diwei[13]={"tret","jan","feb","mar","apr","may","jun","jly","aug","sep","oct","nov","dec"};
	string gaowei[12]={"tam","hel","maa","huh","tou","kes","hei","elo","syy","lok","mer","jou"};
	getchar();
	for(int i=0;i=13){	// >=13
				if(num%13!=0){
					ans[0]=diwei[num%13];
					num/=13;
					ans[1]=gaowei[num%13-1];
					cout<4){	// two numbers of mars 
				string s1,s2;		s1=s.substr(0,3) ;	s2=s.substr(4);
				int i,j;
				for(i=0;i<12;i++)	if(s1==gaowei[i])	break;
				for(j=0;j<13;j++)	if(s2==diwei[j])	break;
				cout<<(i+1)*13+j<

 

你可能感兴趣的:(c,PAT,1044,火星数字)