UVA 11584 "Partitioning by Palindromes"(DP+Manacher)

时间:2024-01-10 11:08:50

传送门

题意  

UVA 11584 "Partitioning by Palindromes"(DP+Manacher)

思路一

  定义 dp[i] 表示 0~i 的最少划分数;

  首先,用马拉车算法求解出回文半径数组;

  对于第 i 个字符 si,遍历 j (0 ≤ j < i),判断以 j 为回文中心的最大回文串是否包含 si

  如果包含,dp[ i ]=min{dp[ i ],dp[2*j-i-1]+1};

Code

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+; char t[maxn];
int r[maxn<<]; struct Manacher
{
char s[maxn<<];
void Init(char *ss,int len)
{
int index=;
s[index++]='#';
for(int i=;i < len;++i)
{
s[index++]=ss[i];
s[index++]='#';
}
s[index]='\0';
}
void mana(char *ss)
{
Init(ss,strlen(ss));
int len=strlen(s);
int R=-;
int C;
for(int i=;i < len;++i)
{
r[i]=R > i ? min(R-i+,r[*C-i]):;
for(;i-r[i] >= && i+r[i] < len && s[i-r[i]] == s[i+r[i]];r[i]++);
if(i+r[i] > R)
{
R=i+r[i]-;
C=i;
}
}
}
}_mana; int dp[maxn];
int Solve()
{
_mana.mana(t); dp[]=;
int len=strlen(t);
for(int i=;i < len;++i)
{
dp[i]=dp[i-]+;
for(int j=;j <= *i;++j)
{ ///t中的第i个字符在预处理后的s数组中的位置为2*i+1
///因为可能由偶回文的情况,所以需要用到'#'
///直接判断在s数组中j的对应的最大回文j+r[j]是否包含2*i+1
///如果包含,再找到2*i+1以j为中心的对称点2*j-(2*i+1)
///判断2*j-(2*i+1)对应于t中的位置的前一个位置(2*j-(2*i+1))/2-1是否在[0,len-1]范围内
///如果在,更新dp[i]
int cur=j+r[j];
int index=(*j-*i-)/-;
if(*i+ < cur)
dp[i]=min(dp[i],+(index >= ? dp[index]:));
}
}
return dp[len-];
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
int test;
scanf("%d",&test);
while(test--)
{
scanf("%s",t);
printf("%d\n",Solve());
}
return ;
}

思路二(reference from zishu)

  定义dp[ i ]表示0~i划分成的最小回文串的个数,则dp[ i ]=min{d[ j ]+1 | j ≤ i && t[ j+1,....,i ]为回文串};

code

 #include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+; char t[maxn];
char s[maxn<<];
bool isPal[maxn][maxn];
int dp[maxn]; void Init()///O(n^2)预处理出t[i,..,j]是否为回文串
{
int len=strlen(t);
for(int i=;i < len;++i)
for(int j=;j < len;++j)
isPal[i][j]=false;
int index=;
s[index++]='#';
for(int i=;i < len;++i)
{
s[index++]=t[i];
s[index++]='#';
}
s[index]='\0'; for(int i=;i < index;++i)
{
int r=;
while(i-r >= && i+r < index && s[i-r] == s[i+r])
{
if((i-r)&)
isPal[(i-r)/][(i+r)/]=true;
r++;
}
}
} int Solve()
{
Init();
int len=strlen(t);
dp[]=;
for(int i=;i < len;i++)
{
dp[i]=dp[i-]+;
for(int j=;j < i;++j)
if(isPal[j][i])
dp[i]=min(dp[i],+(j > ? dp[j-]:));
}
return dp[len-];
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
int test;
scanf("%d",&test);
while(test--)
{
scanf("%s",t);
printf("%d\n",Solve());
}
return ;
}