版权声明:转载请注明出处 https://blog.csdn.net/FSAHFGSADHSAKNDAS/article/details/81592930
链接
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4183
题解
贪心和
相结合
从
刷到
不好想,我们先想怎么从空序列刷到
用
表示从空序列(可以理解为一开始全是*)刷出
序列的最小花费
当
时,我如果把
全刷成
然后再接着刷,这样肯定最优,因为如果我不这样刷,而是先把中间刷好,再刷两头,中间的费用不会更优,刷两端的费用肯定会
。此时
,这样转移的正确性在于,我可以构造一种把
先全刷成
,再接着刷的方案,这个方案和上述所说的是等价的
现在求出了
我令
表示
的前
个字母刷成
的前
个字母的最小花费
当
时,
当
时,
思路总结
这个题学会的新思路有:
- 把一个题拆成两个步骤,分步完成使思维复杂度降低
- 对于区间类型的题目,可以强制分成若干个不相邻的段进行转移
代码
//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;
}