UVa1437&LA4394 StringPainter

错成狗,想漏好几处。
下面本体:
设原串为x,目标串为y
考虑y[i],易知有这么几种情况:
1.x[i]没被涂过色(必有x[i]==y[i])
2.x[i]被涂过色
这时又分为
a.x[i]是某次涂色的开始点
b.x[i]不是某次涂色的开始点(则要从前面某个y[k]==y[i]且被涂过色的k涂过来)
*1:注意“被涂过色”:如果没有这个限定,情况1会混进来,例子:
caa
ccc
1位置虽然颜色对了但是不是涂上的,不加限定答案就成0了
*2:并不一定是从y中i前面第一个满足y[i]==y[k]的地方涂过来,例子:
y=cabcbac 最优方案第3个c应该从第一个涂过来
下面考虑一串全部满足条件2的字符x[i]~x[j]
设f[i][j]表示这串字符涂成y[i]~y[j]的最少次数
考虑最后一个位置j,则j要么是a情况要么是b
若是a,则枚举k,此时就算k+1~j-1中间有y中和j同色的,因为没法涂到j,一定后来又被涂了其他颜色,不用考虑,所以答案为f[i][k]+f[k+1][i-1]
若是b,显然是f[i][j-1]+1
这样O(n^3)可求f[][]
接下来考虑没涂色的怎么办
可以这样:设g[i]表示把1~i涂对的最少次数
可以枚举最近一个没涂色的位置j
则j+1~i都被涂过色,符合f的条件。
g[i]=g[j-1]+f[j+1][i]
当然也有可能都被涂过色g[i]=f[1][i]
于是g[n]就是答案。

#include<stdio.h>
#include<string.h>
#define re(i,l,r) for(int i=l;i<=r;i++)
#define NN 105
#define MA 2000000000
using namespace std;
int f[NN][NN],g[NN],n;
char x[NN],y[NN];
int min(int x,int y){return x<y?x:y;}
int workf(int l,int r)
{
    if(l>r) return 0;
    if(f[l][r]<MA) return f[l][r];
    int ret=MA;
    re(i,l,r-1)
        if(y[i]==y[r]) ret=min(ret,workf(l,i)+workf(i+1,r-1));
    ret=min(ret,workf(l,r-1)+1);
    f[l][r]=ret; return ret;
}
int main()
{
    freopen("prac.in","r",stdin); //freopen("prac.out","w",stdout);
    while(scanf("%s%s",x+1,y+1)==2)
    {
        memset(f,0x7f,sizeof(f)); memset(g,0x7f,sizeof(g));
        n=strlen(x+1); g[0]=0;
        re(i,1,n)
        {
            g[i]=workf(1,i);
            re(j,1,i) if(x[j]==y[j]) g[i]=min(g[i],g[j-1]+workf(j+1,i));
        }
        printf("%d\n",g[n]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值