亲亲串
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
如果有一个字符串,它的前半段等于它后半段,例如 abcabc,我们就叫这种字符串为“亲亲串”。
现在给你一个字符串(仅有大小写字母组成),可以在任意的位置添加任意个字符,使这个字符串成为一个“亲亲串”,最少需要添加多少个字符?
-
输入
-
第一行是一个整数N(0<N<=1000),表示有N组测试数据。
接下来有N行,每行有一个字符串,字符串的长度小于1000;
输出
- 对于每组测试数据输出一个整数,为最小添加字符数 样例输入
-
3 abcbc aaaab abcd
样例输出
-
1 1 4
-
第一行是一个整数N(0<N<=1000),表示有N组测试数据。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*动态规划,将字符串分成两段,然后计算至少添加多少个字符才能使这两段字符串相等
将字符串分段时,是从串的中间向两边遍历,加了剪枝*/
char data[1002]; //存储输入数据
int dp[1002][1002]; //打表用
//对于两个字符串arr1和arr2,计算出至少需要添加几个字符
//arr1:要计算的第一个字符串
//arr1_len:arr1的长度
//arr2:要计算的第二个字符串
//arr2_len:arr2的长度
//return:至少添加字符的个数
int find(char *arr1, int arr1_len, char *arr2, int arr2_len)
{
int temp1, temp2;
if(dp[arr1_len][arr2_len] != -1)
{ //记忆化搜索
return dp[arr1_len][arr2_len];
}
if(arr1_len == 0 || arr2_len == 0)
{
dp[arr1_len][arr2_len] = arr1_len > arr2_len ? arr1_len : arr2_len;
return dp[arr1_len][arr2_len];
}
if(arr1[0] == arr2[0])
{
dp[arr1_len][arr2_len] = find(arr1 + 1, arr1_len - 1, arr2 + 1, arr2_len - 1);
}
else{
temp1 = find(arr1, arr1_len, arr2 + 1, arr2_len - 1);
temp2 = find(arr1 + 1, arr1_len - 1, arr2, arr2_len);
dp[arr1_len][arr2_len] = 1 + (temp1 < temp2 ? temp1 : temp2);
}
return dp[arr1_len][arr2_len];
}
int main()
{
int t ;
int i = 1;//while
int data_len;//输入的字符串的长度
int res;//要输出的结果
int temp;//临时变量
// freopen("in.txt", "r", stdin);
scanf("%d%*c", &t);
while(t --)
{
scanf("%s", data);
data_len = strlen(data);
memset(dp, -1, sizeof(dp));
res = find(data, data_len / 2, data + data_len / 2, data_len - data_len / 2);
i = 1;
//插入位置从中间向两边找,若从左到右会超时,i > res时需要添加的字符个数就一定会大于res,所以不需要继续遍历了
while(i <= res && i <= data_len / 2)
{
memset(dp, -1, sizeof(dp));
temp = find(data, data_len / 2 + i, data + data_len / 2 + i, data_len - data_len / 2 - i);
res = res < temp ? res : temp;
memset(dp, -1, sizeof(dp));
temp = find(data, data_len / 2 - i, data + data_len / 2 - i, data_len - data_len / 2 + i);
res = res < temp ? res : temp;
++ i;
}
printf("%d\n", res);
}
return 0;
}