题目
思路
我们考虑如果简单一点的情况
设\(f[i][j][c]\)表示区间\(i到j\)能不能用字符\(c\)构成
我们设\(c\)能拓展成\(a\)和\(b\)
\(f[i][j][c]|=(f[i][k][a]\&f[k+1][j][b])\)
接着我们考虑对于他们的祖先一个字符一个字符的加入
设\(dp[i][j]\)为\(s_1\)的前i位和\(s_2\)的前\(j\)位的最小祖先长度,
\(dp[i][j]=min\{dp[i_1][j_1]+1[f1[i_1][i][c]\&f2[i_2][j][c]]\}\)
即一个字符拓展成为一个区间
总时间复杂度即为\(O(n^4)\)
代码
#include<iostream>
#include<cstring>
using namespace std;
struct node
{
char a;
char b,c;
}op[55];
int n;
char a[55],b[55];
int lena,lenb;
int f1[55][55][30],f2[55][55][30];
//区间i到j能否用k构造出来
int dp[55][55];
//a的前i个数和b的前j个数的最小长度
int dfs(int f[][55][30],char *a,int l,int r,int ch)
{
if(l==r&&a[l]==ch)
f[l][r][ch]=1;
if(f[l][r][ch]!=-1)
return f[l][r][ch];
for(int i=1;i<=n;i++)
if(op[i].a==ch)
for(int j=l;j<r;j++)
if(dfs(f,a,l,j,op[i].b)==1&&dfs(f,a,j+1,r,op[i].c)==1)
{
f[l][r][ch]=1;
return 1;
}
f[l][r][ch]=0;
return 0;
}
int solve(int la,int lb)
{
if(dp[la][lb]!=-1)
return dp[la][lb];
dp[la][lb]=(1<<30);
for(int k=1;k<=26;k++)
for(int i=0;i<la;i++)
for(int j=0;j<lb;j++)
if(dfs(f1,a,i+1,la,k)==1&&dfs(f2,b,j+1,lb,k)==1)
dp[la][lb]=min(dp[la][lb],solve(i,j)+1);
return dp[la][lb];
}
int main()
{
ios::sync_with_stdio(false);
memset(f1,-1,sizeof(f1));
memset(f2,-1,sizeof(f2));
memset(dp,-1,sizeof(dp));
cin>>(a+1)>>(b+1);
lena=strlen(a+1);
lenb=strlen(b+1);
for(int i=1;i<=lena;i++)
a[i]-='a'-1;
for(int i=1;i<=lenb;i++)
b[i]-='a'-1;
cin>>n;
for(int i=1;i<=n;i++)
{
string a;
cin>>a;
a[0]-='a'-1;
a[3]-='a'-1;
a[4]-='a'-1;
op[i].a=a[0];
op[i].b=a[3];
op[i].c=a[4];
}
dp[0][0]=0;
if(solve(lena,lenb)==1073741824)
cout<<"-1";
else
cout<<solve(lena,lenb)<<endl;
return 0;
}