poj1850

来源:互联网 发布:零点有数科技 知乎 编辑:程序博客网 时间:2024/06/18 16:49

题目不难,大致题意为将26个小写字母(可以小于26)所组成的所有满足题意要求的字符串按照题目要求编码。要求该字符串由小写字母组成,并且是严格升序排列。将所有这样的字符串编码,编码规则如下:

1)按照长度递增编码

2)长度相同时,按照字符串的大小编码

3)字符串的码值即为编码序号

题目要求给出一个串,若是符合题意要求的字符串则求出它的编码值,否则直接输出0。

题意很明确。就是要寻找编码值。关键在于如何求出编码值,分析如下:

可以分成两部分来求编码值:

1)将所有比该字符串长度小的最大编码求出来

2)求解该长度下,该字符串的编号

对于上述两个问题,核心就是如何求解一个长度下的字符串个数。只要把这个弄懂了,就OK了!

对于一个长度下的字符串个数,无非就是从26个字母中取出该长度个数的字符组成字符串,并且是递增字符串的不同个数。这里介绍两种方法:递推法、穷举法(深搜实现)

1)递推法

手算长度为1的个数为26

        长度为2的个数为∑26-i(1<=i<=25)

        长度为3的个数为∑i∑j (26-j)  (2<=i<=25 && i<=j<=25)

        长度为4的个数为∑i∑j∑k (26-k) (3<=i<=25 && i<=j<=25 && j<=k<=25)

        ……

        长度为n的个数为∑∑∑……∑(n-1次求和)(26-n(n-1)) (n-1<=n1<=25 && n1<=n2<=25 && …… )

这个递推式可以很容易的用深搜实现,这里不再多讲,具体看程序。

2) 穷举法

直接用深搜穷举该长度下的所有字符串个数(看程序)

注意穷举法和递推法虽然时间复杂度相差不大,但是前者的递归深度要小一些,所需系统堆栈要少。故所需时间要相对较少。

下面分别是递推法和穷举法的AC时间 :157MS  ,  250MS

下面是代码:(穷举和递推) 132K+157MS

#include <stdio.h>#include <stdlib.h>#include <string.h>#define Max 20char Input[Max]; // 输入char record[Max]; // 辅助数组int Sum,len,lendif; /*void dfs_get_between(int pivot,int index){ // 递推求解if(pivot==0){Sum+=26;return ;}if(pivot==1){for(int i=index;i<=25;i++)Sum+=(26-i);return ;}else{for(int i=index;i<=25;i++)dfs_get_between(pivot-1,i);}}*/bool dfs_get_num(int pivot,int Inf){ // 深搜求解一个长度下该字符串的编码序号if(pivot==len+1){record[len]='\0';Sum++;if(strcmp(record,Input)==0) // 注意若查找到原串,则直接返回,由于要连带返回,故设计成boolreturn true;return false;}// 算法核心,剪枝关键在于:将每个字符的可选范围由(a-z)压缩成比前一个字符大,且同时要保证后面字符有可选字符余地。这样可以保证每个字符串都为递增,且每个字符的枚举顺序都是从小到大,这样也可保证所得同一长度下的字符串均是按升序排列for(int i=Inf+1;i<=26-(len-pivot);i++){  record[pivot-1]=i+'a'-1;if(dfs_get_num(pivot+1,i))return true;}return false;  // 注意回溯}void dfs_get_dif(int pivot,int Inf){ // 区别于上面深搜是无需返回,求所有的字符串个数if(pivot==lendif+1){Sum++;return ;}for(int i=Inf+1;i<=26-(lendif-pivot);i++)dfs_get_dif(pivot+1,i);}bool Is_right(){ // 判断输入的字符串是否合法for(int i=0;i<len-1;i++)if(Input[i]<'a' || Input[i]>'z' || Input[i]>=Input[i+1])return false;if(Input[len-1]<'a' || Input[len-1]>'z')return false;return true;}int main(){scanf("%s",Input);len=strlen(Input);if(!Is_right()){printf("0\n");return 0;}Sum=0; //初始化为0for(int i=1;i<=len-1;i++){ //求解比该长度小的最大编码,两种方法均可//dfs_get_between(i-1,i-1);    lendif=i;dfs_get_dif(1,0);}dfs_get_num(1,0); //求解该长度下的编码序号printf("%d\n",Sum);return 0;}



 

 

  

0 0
原创粉丝点击