《算法竞赛入门经典(第2版)》例题4-4信息解码 (Message Decoding ,UVa213)

先说一下算法:
1、首先利用getchar()读取字符,字符可能包含空,设置在遇到换行符结束,这里会遇到一个问题,第一组输入完毕后结尾又一个回车会出现在下一组字符的第一个,对此可以设定first变量,第一组计算完毕后first=0,如果first=1再做后面的工作,首行的回车使得字符读取函数提前结束了。
下一组循环first=1,读取从第一个字母开始,去掉了上一组输入的影响。
这里还要注意存储字母到二维数组的算法,令二维数组列表示数据长度,行表示大小,每列存储2^n-1个数据,n从1开始向右递增。这是二进制的进位特性决定的
2、利用scanf读取命令序列,命令序列是多行的,但是不存在空,所以可以使用scanf,读取序列,拼接序列,将每一个独立的行整合到一起构成完整序列。
3、二进制转化十进制。
4、解码过程:解码过程需要设置解码长度和读取头,例如00101000序列,第一次的解码长度设置为3,读取头为0,提取出001转二进制为1,更新解码长度1,读取头为2,读取长度为1的的下一个0,计算0的长度为1,二进制对应0,将二维字符数组的对应字符存在一维数组中(这是因为命令段的更新,比如001,01,000分三行输入,直接输出只会重复输出,因为拼接过程如下:001,00101,00101000,通过不断覆盖一维数组得出最终结果),更新读写头为4,比较1是11111的子串(strstr实现),为什么用if(strstr)来说是子串而不是if(!strstr)说不是子串,可能因为NULL的逻辑反未知吧。1是子串,小结结束,通过读取后三位判断解码长度,更新读写头为7,发现000和000相等,结束该组输入并执行输出。(中间还有很多长度的问题和是否需要继续输入的判断,详见代码)。

问题:
1、拼接的问题,重复使用拼接加大了无效计算次数,比如上例拼接结果:001,00101,00101000,第一次读写的过程还需要在下一次再做一遍,一次类推,比如第一次需要做1次,第二次需要做3次,第三次需要做4次,其实完整序列只需要做4次就可以了,但是不断拼接的过程多了1+3=4次,这是非常可怕的。这是因为逻辑上输入终点无法在输入过程中被判断,如果不进行解码是无法知道什么时候输入结束,我不能张口说这是三行输入没有第四行,不经过解码是说不清的,所以每次输入都要配一个解码过程,重复计算的代价就很大了。
2、编写过程遇到的问题很多,不过一一改过来了,比如void和int函数区别,解码之前是想写void改一个全局变量来判断是否需要继续输入,后来发现void在运行过程改了它之后,在后续的顺序结构会被改回来,换成int型就是因为在返回数值后,剩下的顺序结构不会再执行了。

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <iostream>
#include <math.h>
#define maxn 1000
char a1[maxn];//存储字母的
char a2[maxn];//存储数字的
char a3[maxn];//接受数字的
char a4[maxn];//存储准备转化二进制的序列
char a5[100];//全一比较串
char a6[maxn][maxn];//横轴存长度,纵轴存大小
int first=1;
//int o=1;//输入停止标号
using namespace std;

int change(char a[],int n)//二进制转十进制
{
    int s=0;int t=1;
    for(int i=n-1;i>=0;i--)
    {
        s=s+t*(a[i]-'0');
        t=2*t;
    }
    return s;
}

void input_alpha()
{
    int k=1;
    for(int j=0;;j++)
    {   int d=1;
        for(int i=0;i<int(pow(2,k))-1;i++)
        {   //printf("n次方-1等于%d\n",int(pow(2,k))-1);
            a6[i][j]=getchar();
            if(a6[i][j]=='\n'&&i==0&&j==0) {first=0;}
            if(a6[i][j]=='\n') {d=0;break;}

        }
        k++;
        //printf("Yes\n");
        if(!d) {break;}
    }
}

int explain()
{   //printf("Yes\n");
    int dd=0;
    memset(a4,'\0',sizeof(a4));//初始化a4串
    memset(a5,'1',sizeof(a5));//初始化a5串为全1串
    int n=3;//写入多少位到a4串做二进制转换
    int t=0;//确定开始位置
    //printf("a2长=%d\n",int(strlen(a2)));
    while(t<strlen(a2))
    {  if(strlen(a2)>=3)
      {   n=3;int k=0;int i=0;
          if(t+n>strlen(a2)) break;
          for(i=t;i<t+n;i++)
          {
              a4[k]=a2[i];k++;
          }
          t=i-1;
          if(!strcmp(a4,"000"))//如果a4串和000相等停止输入
          {return 0;}
          else
          //最早的三位提取准备转换为十进制
          {n=change(a4,n);}//printf("n=%d\n",n);}
          if(strlen(a2)>=t+n+1)
          {
              while(t<strlen(a2))
              { int j=0;memset(a4,'\0',sizeof(a4));
                for(int i=t+1;i<=t+n;i++)
                {a4[j]=a2[i];j++;}
                t=t+n;
                if(strstr(a5,a4)) //如果a4是1111子串
                {t=t+1;break;}
                else
                {
                     int p=change(a4,n);
                     int pp=int(strlen(a4))-1;
                     //printf("%c",a6[p][pp]);//输出字符
                     a1[dd]=a6[p][pp];dd++;
                }
              }
          }
          else break;
      }
    else {return 1;break;}
    }
    return 1;
}

void input_digit()
{
    while(cin>>a3)
    {
        strcat(a2,a3);
        //printf("%s\n",a2);
        if(!explain()) break;
    }
}

int main()
{
    while(1)
    {   memset(a1,'\0',sizeof(a1));
        memset(a6,'\0',sizeof(a6));
        memset(a2,'\0',sizeof(a2));
        memset(a3,'\0',sizeof(a3));
        memset(a4,'\0',sizeof(a4));
        memset(a5,'\0',sizeof(a5));
        input_alpha();//输入字母序列;
        if(first)
        {
            input_digit();//输入命令序列;
            printf("%s\n",a1);
            
        }
        first=1;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值