B . A Cure for the Common Code kmp + 区间dp

B . A Cure for the Common Code kmp + 区间dp
题目描述
You’ve been tasked with relaying coded messages to your fellow resistance fighters. Each coded message is a sequence of lower-case letters that you furtively scrawl on monuments in the dead of night.

Since you’re writing these messages by hand, the longer the message, the greater the likelihood of being caught by the evil empire while writing. Because of this you decide it would be worthwhile to come up with a simple encoding that might allow for shorter messages. After thinking about it for a while, you decide to use integers and parentheses to indicate repetition of substrings when doing so shortens the number of characters you need to write. For example, the 10 character string

abcbcbcbca

could be more briefly written as the 7 character string

a4(bc)a

If a single letter is being repeated, parentheses are not needed. Also, repetitions may themselves be repeated, so you can write the 20 character string

abbbcdcdcdabbbcdcdcd

as the 11 character string

2(a3b3(cd))

and so forth.

输入描述
Each test case consists of a single line containing a string of lower-case letters of length ≤500. A line containing a single 0 will terminate the input.

输出描述
For each test case, output the number of characters needed for a minimal encoding of the string.

样例
输入 复制
abcbcbcbca
abbbcdcdcdabbbcdcdcd
0
输出 复制
Case 1: 7
Case 2: 11
kmp求周期大佬博客
求周期的话可以做一下这个题
dp[i][j]=min(dp[i][j],dp[i][e]+dp[e][j]),i<e<j;
dp[i][j]:i-j这一段的最小长度;
因为如果i-j里面有循环节的话其实可以再次优化一下,
abbbcdcdcd,abbbcdcdcd -> 2(a3b3(cd))所以在求完dp之后需要用循环节在优化一下。

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int dp[N][N];
char s[N];
int net[N];
void getNext(int l, int len) {
	int i = 0, j = -1;
	net[0] = -1;
	while (i < len) {
		if (j == -1 || s[l + i] == s[l + j]) {
			i++, j++;
			net[i] = j;
		} else
			j = net[j];
	}
}//kmp求next数组的板子
int main() {
	int t = 0;
	while (cin >> s && s[0] != '0') {
		t++;
		int l = strlen(s);
		for (int i = 0; i < l; i++)
		dp[i][i] = 1;
		for (int k = 1; k < l; k++) {
			for (int i = 0; i < l - k; i++) {
				dp[i][i + k] = dp[i + 1][i + k] + 1;
				for (int j = i; j < i + k; j++) {
					dp[i][i + k] = min(dp[i][i + k], dp[i][j] + dp[j + 1][i + k]);
				}
				getNext(i, k + 1);//i-k+1的net
				int cnt = k + 1 - net[k + 1], res;
				if ((k + 1) % cnt == 0) {//其存在循环节详细看超链接
					res = dp[i][i + cnt - 1];//其最小周期对应的最小长度
					if (cnt > 1)res += 2;//存在循环节且长度大于2需要加括号
					cnt = (k + 1) / cnt;//节数
					while (cnt) {
						res++;
						cnt /= 10;
					}加上节数的长度:假设有23个循环节总长度加2
					dp[i][i + k] = min(dp[i][i + k], res);更新
				}
			}
		}
		printf("Case %d: %d\n", t, dp[0][l-1]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值