1. 程式人生 > >1044 火星數字 ——c實現

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()在標頭檔案<stdio.h>

fgets()的典型用法如下:

fgets(buffer,n,stdin)

功能是從標準輸入裝置鍵盤(也就是stdin:stdandard input)讀入n-1個字串。由於字串結尾以"\0"結束,因此必須留出一個,也就是隻能讀入n-1個。buffer可是是提前定義好的陣列的指標,也就是陣列名。

用這種方法可以一次將一行輸入全部讀入buffer快取。但是還沒有進行賦值,因此下面還要將讀入的資訊用於賦值和判斷。更準確地說,是進行判斷和賦值,因此只有先判斷清楚輸入的是火星文還是地球文,才能決定下面怎麼賦值。比如,這裡先判斷讀到的是不是數字,可以用<ctype.h>中的isdigit()函式來進行判斷,如果讀到的是數字,就要進行賦值,然後從數字轉換到火星文。如果讀到的是火星文,也要轉換到地球文。

注意,這裡賦值不能再用scanf()函式,因為scanf會讀入下一個輸入,而非目前讀進到buffer中的輸入。這裡需要用到能將已經讀入快取的資料進行賦值操作,這個函式是sscanf()。百度介紹如下:

sscanf與scanf類似,都是用於輸入的,只是後者以鍵盤(stdin)為輸入源,前者以固定字串為輸入源。sscanf()在標頭檔案<stdio.h>

例如:

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/[email protected]獲取 / 和 @ 之間的字串,先將 "iios/"過濾掉,再將非'@'的一串內容送到buf中

1

2

sscanf("iios/[email protected]""%*[^/]/%[^@]", 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()在標頭檔案<string.h>

原型    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 <string.h>
#include <stdio.h>
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");

3 火星文與地球文之間的轉化

地球文轉到火星文比較簡單,取出對應的高低位,在陣列中查詢即可。由於有了前兩步的基礎,火星文轉地球文也比較簡單,只需要將截斷之後的火星文在建立的火星文字串陣列中遍歷即可,在乘以對應的進位制。

完整程式碼:

//1044 火星數字 V1
#include <stdio.h>
#include <ctype.h>
#include <string.h>

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<n;i++){
		fgets(line,11,stdin);
		if(isdigit(line[0])){	//input is num
			sscanf(line,"%d",&m);
			if(m/13&&m%13)	printf("%s %s\n",tens[m/13-1],units[m%13]);
			if(m/13&&m%13==0)	printf("%s\n",tens[m/13-1]);
			if(m/13==0)		printf("%s\n",units[m%13]);
		}	
		else{	//input is char
			m=Mars2Earth(strtok(line," \n"));
			m+=Mars2Earth(strtok(NULL," \n"));
			printf("%d\n",m);
		}
	}
	return 0;
}