链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4183
题解
贪心和
dp
d
p
相结合
从
s
s
刷到不好想,我们先想怎么从空序列刷到
t
t
用表示从空序列(可以理解为一开始全是*)刷出
t
t
序列的最小花费
当时,我如果把
[i,j]
[
i
,
j
]
全刷成
t[i]
t
[
i
]
然后再接着刷,这样肯定最优,因为如果我不这样刷,而是先把中间刷好,再刷两头,中间的费用不会更优,刷两端的费用肯定会
+1
+
1
。此时
g[i][j]=g[i][j−1]
g
[
i
]
[
j
]
=
g
[
i
]
[
j
−
1
]
,这样转移的正确性在于,我可以构造一种把
i,j−1
i
,
j
−
1
先全刷成
t[i]
t
[
i
]
,再接着刷的方案,这个方案和上述所说的是等价的
现在求出了
g[][]
g
[
]
[
]
我令
f[i]
f
[
i
]
表示
s
s
的前个字母刷成
t
t
的前个字母的最小花费
当
s[i]=t[i]
s
[
i
]
=
t
[
i
]
时,
f[i]=f[i−1]
f
[
i
]
=
f
[
i
−
1
]
当
s[i]≠t[i]
s
[
i
]
≠
t
[
i
]
时,
f[i]=min{f[k]+g[k+1][j]}
f
[
i
]
=
m
i
n
{
f
[
k
]
+
g
[
k
+
1
]
[
j
]
}
思路总结
这个题学会的新思路有:
- 把一个题拆成两个步骤,分步完成使思维复杂度降低
- 对于区间类型的题目,可以强制分成若干个不相邻的段进行转移
代码
//DP
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#define maxn 200
#define inf 0x3f3f3f3f
#define cl(x,y) memset(x,y,sizeof(x))
using namespace std;
int g[maxn][maxn], f[maxn];
char s[maxn], t[maxn], n;
void init()
{
n=strlen(s+1);
cl(g,inf), cl(f,inf);
}
void dp()
{
int i, j, l, k;
for(i=1;i<=n;i++)g[i][i]=1;
for(l=2;l<=n;l++)for(i=1;i+l-1<=n;i++)
{
j=i+l-1;
if(t[i]==t[j])g[i][j]=g[i][j-1];
else for(k=i;k<j;k++)g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
}
f[0]=0;
for(i=1;i<=n;i++)
{
if(s[i]==t[i])f[i]=f[i-1];
else for(j=0;j<i;j++)f[i]=min(f[i],f[j]+g[j+1][i]);
}
printf("%d\n",f[n]);
}
int main()
{
while(~scanf("%s%s",s+1,t+1))init(), dp();
return 0;
}