亲亲串(dp)

亲亲串

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述

如果有一个字符串,它的前半段等于它后半段,例如 abcabc,我们就叫这种字符串为“亲亲串”。

现在给你一个字符串(仅有大小写字母组成),可以在任意的位置添加任意个字符,使这个字符串成为一个“亲亲串”,最少需要添加多少个字符?

输入
第一行是一个整数N(0<N<=1000),表示有N组测试数据。
接下来有N行,每行有一个字符串,字符串的长度小于1000;
输出
对于每组测试数据输出一个整数,为最小添加字符数
样例输入
3
abcbc
aaaab
abcd
样例输出
1
1
4
#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;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值