Alphacode(阿爾法編碼-分治法)

將字母A-Z編碼,A爲1,B爲2,……依此類推,Z爲26;則ABC編碼爲123。但是反向解碼時,解碼結果不唯一,比如123可以解碼爲1-2-3:ABC,解碼爲12-3:LC,解碼爲1-23:AW(注意,127不能解碼爲1-27,因爲範圍只能爲1-26)。
 
現給出一組編碼後的數字串,讓你求該數字串可以有幾種解碼方式(上例中,123對應着3種解碼方式)。問題輸入將保證其爲一個合法的數字串。比如100是一個不合法的數字串,因爲0或者00不代表一個字母;此外01不能視爲1。
 
Sample Input
25114
1111111111
3333333333
Sample Output
6
89
1

 
【解題思路】

算法設計與分析上剛學了分治法,就想拿來試試手,就找了這題。
一開始覺得這題應該用搜索,但超時。後改用分治,遞歸。以25114爲例:
25114共有幾種解碼方式,可以取決於它的前綴解碼方式數*後綴解碼方式數。
也就是Num(25114)=(Num(251)*Num(14 ) 【1】(每次都從中間開始分段);如果251有3種解碼方式,14有2種解碼方式,則25114有2*3=6種解碼方式。然後依次遞歸下去。
 
但是別忘了,25114從25|114出分開,而中間的子串“51”本身是否是一個編碼,而不應該只算分開時的Num(當然本例中51本身不是編碼)。比如22114,22|114如果按照上述算法共有2*3=6種解碼方式,但是子串“21”本身可以作爲一種編碼,那麼22114的遞歸式就該加上這種考慮,變形爲:
Num(22114)=Num(221)*Num(14)+Num(22)*1*Num(4)---【2】;其中1代表“11”子串。
 
除了這點考慮,別忘了裏面含0的情況,要知道“02”不能代表“2”;所以一般裏面有0的情況,0一般只能和前面那個數字組成合法的編碼(題目保證0前面必須是1或者2,組成10和20)。
 
所以在考慮中央分段的那個子串時(比如25114中,“51”是中央子串;123456中“34”是中央子串),就得考慮含0的情況。比如1010這個例子中,中央子串“01”第一個字符爲0,則它的遞歸式和【1】等同。如果在111012這個例子裏,中央子串變爲“10”,其中第二個字符爲0,則其遞歸式爲Num(111010)=Num(11)*1*Num(12)---【3】。

 

發現好久沒有做題了,習慣都丟了,首先數組定義的要足夠大,已經主函數裏,還是要加上返回類型的return 0;(養成良好的習慣)

題目地址:

百鍊:http://poj.grids.cn/practice/2033/(數組定義不夠大)

北京大學ACM:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2202(返回值很重要)

#include<stdio.h>
int Num(char a[],int start,int end)
{
	int len=start+end;
	if(end-start<0)return 1;
	else if(end-start==0)
	{
 		if(a[start]==48)return 0;
		else 
		return 1;
	}
	else
	{
		int half=len/2;
		if(a[half]==48||a[half]>50||(a[half]==50&&a[half+1]>54))
		return Num(a,start ,half)*Num(a,half+1,end);
		else 
		return Num(a,start ,half)*Num(a,half+1,end)+Num(a,start,half-1)*1*Num(a,half+2,end);
	}
}
int main()
{
	char Alphacode[500];
	int i;
	while(scanf("%s",Alphacode)&&Alphacode[0]!=48)
	{
		i=0;
		while(Alphacode[i]>47&&Alphacode[i]<58)
		i++;
		printf("%d\n",Num(Alphacode,0,--i));
	}
	return 0;
}


 

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