HOJ 4300 Clairewd’s message(扩展KMP)

扩展KMP
题目意思:
首先给出 26 个小写字母(这是密文),每个小写字母只出现一次。 第一个小写字母 对应的明文是 ‘a’, 第二个是 ‘b’。
依次类推。 题目的第2个样例的第1个字符串:qwertyuiopasdfghjklzxcvbnm, 那么 ‘q’ 的明文 是 ‘a’, ‘w’ 的明文是 ‘b’ …
第二个字符串, 由两部分组成,第一部分 是 全部的密文, 第二部分是部分的明文(部分明文, 全部明文,或者没有明文)。
问最短可能的字符串是 哪个。

本题要点:
1、以第二个样例为例子:
第2条字符串 “qwertabcde”(假设为 s1) , 将其全部看成是密文,全部转化为明文 “abcdekxvmc”(假设为 s2),
当 s1 的某个后缀 和 s2 的某个前缀 相等时候,说明 这部分相等的,可能是 原来字符串的部分明文。
然后,题目就转化为,求 s1 s1 的某个后缀 和 s2 的某个前缀相等 的最大长度。 但是,有个条件必须注意到,
s1 中, 密文的长度,至少是 s1 长度的一半。 所以,算 s1 的后缀的时候,必须从一半的位置开始算。
2、扩展KMP:
s1 为母串,s2 为子串,求出 s1 字符串extend 数组。从 超过 s1 一半的位置 k 开始扫描, 当 extend[k] 能到达
s1 串的末尾时候,就满足条件。 此时 extend[k] + k == len(s1 的长度)。
当所有扫描的点k 都不满足,说明,s1 串全部是 密文。
3、 输出源字符串的密文 和 明文。s1 部分输出密文, s2 部分输出明文。 通过吧某些位置的字符改为 ‘\0’, 然后
printf("%s") 输出。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 100010;
char s[30], s1[MaxN], s2[MaxN];
int Next[MaxN], extend[MaxN];
char trans[256];
int T;

void init()
{
	int len = strlen(s);
	for(int i = 0; i < len; ++i)
	{
		trans[s[i] + 0] = i + 'a';
	}
	len = strlen(s1);
	for(int i = 0; i < len; ++i)
	{
		s2[i] = trans[s1[i] + 0];
	}
	s2[len] = '\0';
}

//预处理next 数组
void getNext(char* str)
{
	int i = 0, j, po, len = strlen(str);
	Next[0] = len;	
	while(i + 1 < len && str[i] == str[i + 1])	// 计算 next[1]
		++i;
	Next[1] = i;
	po = 1;	//初始化 po位置
	for(int i = 2; i < len; ++i)
	{
		if(Next[i - po] + i < Next[po] + po)	//第一种情况
		{
			Next[i] = Next[i - po];
		}else{
			j = Next[po] + po - i;	
			if(j < 0)
				j = 0;	//如果i>po+next[po],则要从头开始匹配
			while(i + j < len && str[j] == str[j + i])
				++j;
			Next[i] = j;
			po = i;
		}
	}
}

//计算extend 数组
void exkmp(char* s1, char* s2)	// s2 是子串,s1是母串
{
	int i = 0, j, po, len = strlen(s1), l2 = strlen(s2);
	getNext(s2);
	while(i < l2 && i < len && s1[i] == s2[i])
		++i;
	extend[0] = i;
	po = 0;	//初始化po的位置
	for(i = 1; i < len; ++i)
	{
		if(Next[i - po] + i < extend[po] + po)
		{
			extend[i] = Next[i - po];
		}else{
			j = extend[po] + po - i;
			if(j < 0)
				j = 0;
			while(i + j < len && j < l2 && s1[j + i] == s2[j])
			{
				++j;
			}
			extend[i] = j;
			po = i;
		}
	}
}

void solve()
{
	init();
	exkmp(s1, s2);
	int len = strlen(s1);
	bool flag = false;
	int index = 0;
	for(int i = (len + 1) / 2; i < len; ++i)
	{
		if(extend[i] + i == len)	
		{
			flag = true;
			index = i;
			break;
		}
	}
	if(flag)
	{
		s1[index] = '\0', s2[len - extend[index]] = '\0';
		printf("%s%s\n", s1, s2);
	}else{
		printf("%s%s\n", s1, s2);
	}
}

int main()
{
	scanf("%d", &T);
	while(T--)
	{
		scanf("%s%s", s, s1);
		solve();
	}
	return 0;
}

/*
2
abcdefghijklmnopqrstuvwxyz
abcdab
qwertyuiopasdfghjklzxcvbnm
qwertabcde
*/

/*
abcdabcd
qwertabcde
*/

猜你喜欢

转载自blog.csdn.net/qq_38232157/article/details/108433657