CodeForces - 49E Common ancestor(dp)

来源:互联网 发布:js点击左右切换div 编辑:程序博客网 时间:2024/05/22 10:29

题意:有n个替换规则,2个字母可以被替换成一个字母,给出2个串,问这2个串经过一系列的替换后形成的最短且相同的串长度是多少。

做法:我们可以先用区间dp,d[i][j][k]代表i到j区间是否可以变成k这个字母。再利用vector去存一下起点为i,变成k这个字母的终点为哪些,然后就可以进行后来的dp了。设dp[i][j]为第一个串用了i个字母,第二个串用了j个字母经过替换变成相同的串的最短长度。转移就是枚举下一个字母是什么,对于某个dp[i][j],第一个串起点就是i+1,需要利用刚才的vector去找变成枚举的字母的终点。第二个串就是起点是j+1,一样。更新dp[x][y] = min(dp[x][y], dp[i][j]+1)。最后答案就是dp[len1][len2]。

AC代码:

//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cstdlib>#include<stack>#include<queue>#include<set>#include<map>#include<cmath>#include<ctime>#include<string.h>#include<string>#include<sstream>#include<bitset>using namespace std;#define ll __int64#define ull unsigned long long#define eps 1e-8#define NMAX 10000000#define MOD 1000000007#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define PI acos(-1)#define mp make_pairtemplate<class T>inline void scan_d(T &ret){    char c;    int flag = 0;    ret=0;    while(((c=getchar())<'0'||c>'9')&&c!='-');    if(c == '-')    {        flag = 1;        c = getchar();    }    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();    if(flag) ret = -ret;}char s1[55],s2[55],tmp[10];int sub[55][3],n;bool dp1[55][55][30],dp2[55][55][30];vector<int>v1[55][30],v2[55][30];vector<int>::iterator it1,it2;void getdp(char *s, int len, bool dp[][55][30], vector<int> v[][30]){    for(int i = 1; i <= len; i++)        dp[i][i][s[i]-'a'] = 1;    for(int L = 2; L <= len; L++)        for(int i = 1; i + L - 1 <= len; i++)            for(int k = i; k < i+L-1; k++)                for(int j = 1; j <= n; j++)                    dp[i][i+L-1][sub[j][2]] |= dp[i][k][sub[j][0]]&&dp[k+1][i+L-1][sub[j][1]];    for(int i = 1; i <= len; i++)        for(int j = i; j <= len; j++)            for(int k = 0; k < 26; k++) if(dp[i][j][k])                v[i][k].push_back(j);}int dp[55][55];int main(){#ifdef GLQ    freopen("input.txt","r",stdin);//    freopen("o.txt","w",stdout);#endif    scanf("%s%s",s1+1,s2+1);    scanf("%d",&n);    for(int i = 1; i <= n; i++)    {        scanf("%s",tmp);        sub[i][0] = tmp[3]-'a';        sub[i][1] = tmp[4]-'a';        sub[i][2] = tmp[0]-'a';    }    int len1 = strlen(s1+1), len2 = strlen(s2+1);    memset(dp1,0,sizeof(dp1));    memset(dp2,0,sizeof(dp2));    for(int i = 1; i <= 55; i++)        for(int j = 0; j < 30; j++)        {            v1[i][j].clear();            v2[i][j].clear();        }    getdp(s1,len1,dp1,v1);    getdp(s2,len2,dp2,v2);    for(int i = 0; i <= len1; i++)        for(int j = 0; j <= len2; j++)            dp[i][j] = 100;    dp[0][0] = 0;    for(int i = 0; i < len1; i++)        for(int j = 0; j < len2; j++) if(dp[i][j] != 100)            for(int k = 0; k < 26; k++)                for(it1 = v1[i+1][k].begin(); it1 != v1[i+1][k].end(); it1++)                    for(it2 = v2[j+1][k].begin(); it2 != v2[j+1][k].end(); it2++)                        dp[*it1][*it2] = min(dp[*it1][*it2],dp[i][j]+1);    if(dp[len1][len2] == 100) printf("-1\n");    else printf("%d\n",dp[len1][len2]);    return 0;}


0 0
原创粉丝点击