UVa1437&LA4394 StringPainter

来源:互联网 发布:mysql dmg for mac 编辑:程序博客网 时间:2024/06/01 21:46

错成狗,想漏好几处。
下面本体:
设原串为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 2000000000using 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
原创粉丝点击