【gomj】【DP】 小学生语文题
题目
解题思路
设f[i][j]为第一段的 i~n 能从第二段的 j~n 中匹配出来
转移分为三种情况
- x[i]==y[j] 当前俩字符刚好一样,直接从[i+1][j+1]转移
已经一样 所以不需要操作 - x[i]能在y[j~n]中找到且没用过 从f[i+1][j]转移
能在之前的匹配段中找到 说明已经用过操作了 - 当前字符不一样 且不能在之前的匹配段找到 说明 j 往前了仍未匹配到x[i] 进行操作 从f[i][j+1]+1转移
设g[i][j][0/1]记录从哪个状态转移到当前的
找到俩字符相同的情况
然后将不是俩字符相同的情况的字符出现记录下来
统计答案时 如果是俩字符相同的情况 但当前匹配不一样 那么就记录下来具体从哪拿
如果最后还剩有字符 就都往第一位扔
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int w,n,f[2010][2010],g[2010][2010][3];
int p[2][2010][30],zc[30][2010],d[2010],ans[2010][2];
char x[2010],y[2010];
int main()
{
freopen("chinese.in","r",stdin);
freopen("chinese.out","w",stdout);
scanf("%d",&w);
while (w--)
{
memset(g,0,sizeof(g));
memset(zc,0,sizeof(zc));
memset(p,0,sizeof(p));
memset(f,127,sizeof(f));
memset(d,0,sizeof(d));
memset(ans,0,sizeof(ans));
scanf("%s%s",x+1,y+1);
n=strlen(x+1);
for (int i=n;i>0;i--)
{
for (int j=0;j<26;j++)
{
p[0][i][j]=p[0][i+1][j];
p[1][i][j]=p[1][i+1][j];
}
p[0][i][x[i]-'a']++;
p[1][i][y[i]-'a']++; //统计出现次数
}
for (int i=n+1;i>0;i--)
f[n+1][i]=n+1-i; //赋初值
for (int i=n;i>0;i--)
{
for (int j=n;j>0;j--)
{
if (f[i+1][j]!=f[0][0]&&p[1][j][x[i]-'a']-p[0][i+1][x[i]-'a']>0&&f[i][j]>f[i+1][j])
{
f[i][j]=f[i+1][j];
g[i][j][0]=i+1,g[i][j][1]=j;
}
if (f[i+1][j+1]!=f[0][0]&&x[i]==y[j]&&f[i][j]>f[i+1][j+1])
{
f[i][j]=f[i+1][j+1];
g[i][j][0]=i+1,g[i][j][1]=j+1;
}
}
for (int j=n;j>0;j--)
if (f[i][j+1]!=f[0][0]&&f[i][j]>f[i][j+1]+1)
{
f[i][j]=f[i][j+1]+1;
g[i][j][0]=i,g[i][j][1]=j+1;
}
}
printf("%d\n",f[1][1]);
int l=1,r=1,hou=n,t=0;
while (l!=n+1)
{
while (g[l][r][0]==l) r=g[l][r][1];
if (g[l][r][1]!=r) d[r]++,r++;
l++;
}
for (int i=1;i<=n;i++)
{
d[i]=d[i]^1;
if (d[i])
{
int k=y[i]-'a';
zc[k][++zc[k][0]]=i;
}
}
for (int i=n;i>0;i--)
{
if (!hou) break;
if (!d[i])
{
while (x[hou]!=y[i])
{
int k=x[hou]-'a';
ans[++t][0]=zc[k][zc[k][0]--];
ans[t][1]=i+1;
hou--;
}
hou--;
}
}
for (int i=hou;i>0;i--)
{
int k=x[i]-'a';
ans[++t][0]=zc[k][zc[k][0]--];
ans[t][1]=1;
}
for (int i=1;i<t;i++)
for (int j=i+1;j<=t;j++)
{
if (ans[i][0]>=ans[j][0]&&ans[j][0]>=ans[i][1]) ans[j][0]++;
if (ans[i][0]>ans[j][1]&&ans[j][1]>ans[i][1]) ans[j][1]++;
}
for (int i=1;i<=t;i++) printf("%d %d\n",ans[i][0],ans[i][1]);
}
}