字符串折叠

该题与一般的区间dp有点区别在于我们的dp值是由该序列可否折叠得来,与一般的动态规划的转移方程是不一样的,这题区间的dp值体现从i到j最小的折叠数,可能这个折叠有1也就是不折叠,或者2,3,4取决于这个序列的长度,所以我们的dp值是由更小的序列最优值得来的,所以很明显我们需要使用区间dp的思想。

// 字符串折叠.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 200;
string s;
int d[maxn][maxn];
bool check(string s,int n,int len)//该函数判断这个序列是否可以折叠len的长度
{
	for (int i = len;i < n;i++)
	{
		if (s[i] != s[i%len])return false;//我们每次与序列的前len个项进行对比,将序列后面几个len值全部比较完毕,如果有一个不符合,
		//那么直接返回false
	}
	return true;
}
int main()
{
	cin >> s;
	memset(d, 0x3f, sizeof(d));
	for (int i = 0;i < s.length();i++)
	{
		d[i][i] = 1;//很明显自己和自己可以折叠变成1
	}
	for (int length = 2;length <= s.length();length++)//区间dp的固定套路
	{
		for (int i = 0,j = i + length - 1;j<s.length();j++,i++)//这里我们使用了string,所以起止位置是从0开始的
		{//相应的i与j的写法就要有相应的区别
			for (int k = i;k < j;k++)
			{
				d[i][j] = min(d[i][j], d[i][k] + d[k + 1][j]);
			}
			for (int k = i;k < j;k++)//这就是与我之前做过的区间dp不一样的地方,我们需要看这一个序列里的各段(长度可以有1-n),
				//后面有判断,是否可以折叠,然后折叠长度的最小值
			{
				int len = k-i + 1;
				if (length%len != 0)
				{//看看能不能len长度将序列整分
					continue;
				}
				if (check(s.substr(i), length, len))//小序列起点位置不一定在0,所以起点是i开始,len是将序列分为len长度
					//length也就是序列的最大值
				{
					int temp = (j - i + 1) / (k - i + 1);//前面要加一个数表明序列分段的段数,可能有两位数三位数
					if (temp / 100 != 0)
					{
						temp = 3;
					}
					else if (temp / 10 != 0)
					{
						temp = 2;
					}
					else
					{
						temp = 1;
					}
					d[i][j] = min(d[i][j], d[i][k] + 2 + temp);//这才是状态转移方程
				}
			}
		}
	}
	cout << d[0][s.length() - 1];
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值