回 帖 发 新 帖 刷新版面

主题:acm程序.

/*
该程序出自某高人的blog,不知道具体算法是什么.望请那位大人帮忙解释下

Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗? */


#include<stdio.h>
#include<string.h>
#include<memory.h>
//#include<assert.h>
#define MAX_LEN 80
char szInput[MAX_LEN+1];
unsigned char B[(MAX_LEN+1)*MAX_LEN/8];//感觉跟Bit8有关系,但具体说不出来什么
unsigned char Bit8[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};//看来是"位"操作
#define GETB(i,j) (B[(i)*10+((j)>>3)] & Bit8[(j) & 0x7])
#define SETB(i,j) (B[(i)*10+((j)>>3)] |= Bit8[(j) & 0x7])
int length;
int getcode()
{
 int i,j,notfound1,notfound2=0;
 if(length<2)
  return 1;   //如果只输入两个字符,则返回1
 memset(B,0,(length+1)*10);//MAX_LEN/8?
 for(i=0;i<2;++i)
 {
  for(j=0;j<length;++j)
   SETB(i,j);//B[i][j]=1;
 }
 for(i=2;i<=length;++i)
 {
  for(notfound1=1,j=0;j<=length-i;++j)
  {
   if(GETB(i-2,j+1)/*B[i-2][j+1]*/ && szInput[j]==szInput[j+i-1])
   {
    SETB(i,j);//B[i][j]=1;
    //printf("%d,%d = 1\n",i,j);
    notfound1=0;
   }
  }
  if(notfound1)
  {
   if(notfound2)
    return i-2;
   notfound2=1;
  }
  else
  {
   notfound2=0;
  }
 }
 if(notfound2)
  return length-1;
 return length;
}

int main(void)
{

 while(scanf("%s",szInput)!=EOF)
 {
  length=strlen(szInput);
  //assert(length<=MAX_LEN);
  printf("%d\n",getcode());
 }
    return 0;
}

回复列表 (共2个回复)

沙发

这个题属于回文方面的

板凳

#include<stdio.h>
#include<string.h>
#include<memory.h>
//#include<assert.h>

#define MAX_LEN 80
char szInput[MAX_LEN+1];
unsigned char B[(MAX_LEN+1)*MAX_LEN/8];        // 通过Bit8来操作某个字节的任意一位
unsigned char Bit8[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};    //看来是"位"操作
#define GETB(i,j) (B[(i)*10+((j)>>3)] & Bit8[(j) & 0x7])    // 这儿i相当于回文串的长度,j相当于回文串的起始位置。SETB(i,j)即检查字符串j位置是否有一个长度为i的回文串
#define SETB(i,j) (B[(i)*10+((j)>>3)] |= Bit8[(j) & 0x7])    // 同上。SETB(i,j)即设置字符串的j位置开始有一个长度为i的回文串

int length;

int getcode()
{
    int i,j,notfound1,notfound2=0;

    if(length<2)
        return 1;   //如果只输入两个字符,则返回1

    memset(B,0,(length+1)*10);    // 10 = MAX_LEN/8

    // 由于长度为0和1的必定就是回文串,因此初始化i=0,1的情况
    for(i=0;i<2;++i)
    {
        for(j=0;j<length;++j)
            SETB(i,j);    
    }

    // 逐步考察看看是否有更长的回文串
    for(i=2;i<=length;++i)    
    {
        // notfound1标记用于检查在某一轮中是否出现更长的回文串
        for(notfound1=1,j=0;j<=length-i;++j)
        {
            // 如果j位置的字符与j+i-1位置的字符相等,并且j+1位置原先有长度为i-2的回文串,
            // 就说明j位置开始的长度为i的字符串就是回文串。之所以不用GETB(i-1,j+1)是因为
            // 回文串一增加就是2个字符
            if(GETB(i-2,j+1) && szInput[j]==szInput[j+i-1])
            {
                SETB(i,j);
                notfound1=0;    // 找到一个更长回文串
            }
        }
        if(notfound1)
        {
            if(notfound2)    // 如果有连续两轮没增加长度,说明不存在更长的回文串,此时可以直接返回
                return i-2;
            notfound2=1;    // 本轮没出现更长回文串,看看下一轮还出现不?
        }
        else
        {
            notfound2=0;    // 本轮已出现更长回文串,就不存在下一轮的问题了
        }
    }
    if(notfound2)            // 最后一轮没出现更长回文串就退出了循环(即只有倒数第2轮出现更长回文串)
        return length-1;
    return length;
}

int main(void)
{
    
    while(scanf("%s",szInput)!=EOF)
    {
        length=strlen(szInput);
        //assert(length<=MAX_LEN);
        printf("%d\n",getcode());
    }
    return 0;
}

我来回复

您尚未登录,请登录后再回复。点此登录或注册