1. 程式人生 > >【openjudge】切割回文

【openjudge】切割回文

描述

阿福最近對迴文串產生了非常濃厚的興趣。

如果一個字串從左往右看和從右往左看完全相同的話,那麼就認為這個串是一個迴文串。例如,“abcaacba”是一個迴文串,“abcaaba”則不是一個迴文串。

阿福現在強迫症發作,看到什麼字串都想要把它變成迴文的。阿福可以通過切割字串,使得切割完之後得到的子串都是迴文的。

現在阿福想知道他最少切割多少次就可以達到目的。例如,對於字串“abaacca”,最少切割一次,就可以得到“aba”和“acca”這兩個迴文子串。

輸入 輸入的第一行是一個整數 T (T <= 20) ,表示一共有 T 組資料。
接下來的 T 行,每一行都包含了一個長度不超過的 1000 的字串,且字串只包含了小寫字母。 輸出 對於每組資料,輸出一行。該行包含一個整數,表示阿福最少切割的次數,使得切割完得到的子串都是迴文的。 樣例輸入
3
abaacca
abcd
abcba
樣例輸出
1
3
0
提示 對於第一組樣例,阿福最少切割 1 次,將原串切割為“aba”和“acca”兩個迴文子串。
對於第二組樣例,阿福最少切割 3 次,將原串切割為“a”、“b”、“c”、“d”這四個迴文子串。
對於第三組樣例,阿福不需要切割,原串本身就是一個迴文串。

其實一直不是很擅長字串動規的題目

其實這道題的思路很簡單。ok是判斷迴文。相當於一個劃分型dp,f[i]表示前i個的最優值。貌似普通的劃分性dp(二維陣列)不能用,會T。

其實用一維陣列和兩重迴圈可以解決。因為如果當前無法滿足的話以後一定也會列舉到。

注意是每一段都是迴文。

【程式碼】

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int t,f[1005],len;
char s[1005];
inline bool ok(int l,int r){
	int lo=r-l+1;
	for (int i=l;i<=(l+r)/2;++i)
	  if (s[i]!=s[r-(i-l+1)+1]) return false;
	return true;
}
int main(){
	scanf("%d\n",&t);
	while (t--){
		gets(s); len=strlen(s);
		for (int i=len;i>=1;--i) s[i]=s[i-1];
		memset(f,127/3,sizeof(f));
		for (int i=1;i<=len;++i)
		  if (ok(1,i)) {f[i]=0; continue;}
		  else for (int j=1;j<i;++j)
		    if (ok(j+1,i)) f[i]=min(f[j]+1,f[i]);
		printf("%d\n",f[len]);
	}
}