劉汝佳算法競賽入門 ACM/ICPC UVa213 信息解碼

- 題目

對於下面這個字符串:
0,00,01,10,000,001,010,011…….
首先是長度爲1的串,然後是長度爲2的串,以此類推。不存在全爲1的串。
你的任務是編寫一個程序。首先輸入一個代碼頭(例如AB#TANCnrtXc),則上述序列的每個串依次對應編碼頭的每個字符。例如,0對應A,00對應B,01對應#…,0000對應c。接下來是編碼文本(可能由多行組成,你應當把他們拼成一個長長的01串)。編碼文本由多個小節組成,每個小節的前3個數字代表小節中每個編碼的長度,用二進制表示,然後是個字符的編碼,以全1結束。編碼文本以000結束。

思路:
①讀入代碼頭並處理 (用一個子函數讀取,並對代碼頭進行處理,用codes[len][十進制數]來記錄對應的代碼頭,如code[1][0]代表長度爲1,十進制爲0即二進制數‘0’ 所對應的字符;code[2][1]代表長度爲2,十進制爲1即二進制數爲‘01’所對應的字符)
②讀入三個數來確定長度len
③讀入len長的二進制數,並將其轉爲十進制;如果len長二進制數=111…(len個1),說明該小節結束,回到②重新判斷長度len,繼續③操作

總結以上需要到的函數:
①讀取代碼頭並處理 int readcodes();
②讀取單個字符 int readchar();
③將len長度的二進制數轉十進制 int readint()
④測試輸出函數//可寫可不寫,主要用來測試糾錯 void printfcodes();

考慮完思路和所需的子函數,要再想一下一些特殊情況、循環條件、結束條件

特殊情況:所輸入的編碼文本有可能是多行的,要用getchar自動忽略掉回車、換行鍵。

循環條件:當讀入len長二進制數=111…(len個1)時,一個小節結束,重新判斷三個數獲取len,判斷小節是否結束語句:(設len長二進制數的對應十進制數爲v) if(v==((1<<len)-1)) 進入下一個循環 判斷len;

拓展 在C語言中,“乘以2”也可以寫成“<<1”,意思是“左移一位”。 故1<<len 等於2^len。 例如:1<<2等於 2^2=4

結束條件:讀入三個數來確定長度len時,如果len==0,即len的二進制數爲000時,結束解碼。

好了所有思路都捋清楚,所有細節都整理好之後,就可以寫代碼了。

#include<bits/stdc++.h>
using namespace std;
char codes[8][1<<8-1];//codes[len(串的長度)][對應的十進制數],具體用法在前面和readcodes函數都寫有
int readchar()//用於讀取一個字符
{
	for(;;)
	{
		char ch=getchar();
		if(ch!='\n'||ch!='\r')
			return ch;
	}

	
 } 
int readcodes()//讀取代碼頭
{
	memset(codes,0,sizeof(codes));//置0
	codes[1][0]=getchar();//代碼頭第一個元素就是‘0’對應的字符
	for(int len=2;len<=7;len++)//拿len=2舉例,len=2的二進制有00,01,10(11是小節終止判斷,不算在裏面),其對應的十進制分別爲0,1,2;(1<<len)-1=2^2-1=3;
	{
		for(int i=0;i<((1<<len)-1);i++)
		{
			char ch=getchar();
			if(ch==EOF) return 0;//如果輸入完了代碼頭,按了ctrl+Z(即判斷==EOF了),結束進程,就沒有後面的編譯文本的輸入,直接return 0退出程序就好了
			if(ch=='\n'||ch=='\r') return 1;//碰到換行符,說明代碼頭輸入完畢,return 1,輸入編碼文本
			codes[len][i]=ch;
		}
	}
	return 1;
	 
}
int readint(int len)//讀取len個字符後將其轉化爲十進制 
{
	int sum=0;//特別注意:這種sum一定要初始化爲0,不然很容易出錯,不然你試試看
	while(len--)
	{
		sum=sum*2+readchar()-'0';//101 (二進制) =((1*2+0)*2+1=5(十進制)自行理解?
	}
	return sum;
}
void printfcodes()//用於測試 
{
	for(int len=1;len<=7;len++)
	{
		for(int i=0;i<((1<<len)-1);i++)
		{
			if(codes[len][i]==0) return ;//因爲提前置0過了,碰到0,說明字符已經輸出完畢了,直接結束就可以了
			cout<<codes[len][i];
		}
	 }	 
} 
int main()
{
	while(readcodes())//輸入編譯頭
	{
		//printfcodes();//測試用
		for(;;)
		{
			int len=readint(3);//獲取每個編碼的長度
			if(len==0) break;//如果len二進制==000編碼結束
			 //printf("%d\n",len);//測試用
			for(;;)
			{
				int v=readint(len);//獲取len長度二進制,並轉爲十進制
				//cout<<v<<endl;//測試用
				if(v==((1<<len)-1)) break;//if=1.... 小節結束
				putchar(codes[len][v]);
			}
			//cout<<endl;
		}
		printf("\n");
	} 
	return 0;
}

總結

這道題就是把思路給想好,把要用的子函數想好,再考慮一些細節性的東西。這道題做完了之後其實想想不難,重點是二進制的處理問題。還有采用自頂而下的方法,先寫框架,再寫細節。

啊!蒻蒻終於寫完這篇辣雞題解了。開森!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章