1. 程式人生 > >1090: [SCOI2003]字串摺疊

1090: [SCOI2003]字串摺疊

摺疊的定義如下: 1. 一個字串可以看成它自身的摺疊。記作S  S 2. X(S)是X(X>1)個S連線在一起的串的摺疊。記作X(S)  SSSS…S(X個S)。 3. 如果A  A’, BB’,則AB  A’B’ 例如,因為3(A) = AAA, 2(B) = BB,所以3(A)C2(B)  AAACBB,而2(3(A)C)2(B)AAACAAACBB 給一個字串,求它的最短折疊。例如AAAAAAAAAABABABCCD的最短折疊為:9(A)3(AB)CCD。

Input

僅一行,即字串S,長度保證不超過100。

Output

僅一行,即最短的摺疊長度。

Sample Input

NEERCYESYESYESNEERCYESYESYES

Sample Output

14

HINT

 

一個最短的摺疊為:2(NEERC3(YES))

思路:

f[i][j] 代表 i 到 j 之間的摺疊成最小的長度。 

首先我們要判斷是不是有摺疊的。 

如果有,判斷摺疊多少次,因為是有數字在裡面的。要計算數字的位數。 

如果不能摺疊,有列舉 k 的位置,然後用區間動規做出來。 

 

#include<bits/stdc++.h>
using namespace std;
char s[200];
int tot;
int f[200][200];
bool check(int x, int y,int z){
	if ((y - x + 1) % (z - x +1)) return 0; //是夠整除。
	for (int i = x; i <= y; i++)
	if (s[i] != s[(i-x)%(z-x+1) + x]) return 0;	//判斷是不是重複的,
	int tt = (y - x + 1) / (z - x + 1); //有多少個重複的。 
	tot = 0;
	while(tt){ //判斷有幾位數。
		tt /= 10;
		tot++;
	} 
	return 1;
}


int main(){
	int n;
	scanf("%s",s);
	n = strlen(s);
	for (int i = 0; i < n; i++) f[i][i] = 1;
	for (int len = 2; len <= n; len++){
		for (int i = 0; i <= n - len; i++){
			int j = i + len - 1;
			f[i][j] = len; //初始化。
			for (int k = i; k < j; k++){
				if (check(i,j,k))	f[i][j] = min(f[i][j],f[i][k] + 2 + tot); //如果重複。
				f[i][j] = min(f[i][j], f[i][k] + f[k+1][j]); //不重複,直接加起來。
			}
		}
	}
	printf("%d\n",f[0][n-1]);
	return 0;
}