CodeForces - 49E Common ancestor(dp)

題意:有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_pair
template<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;
}


發佈了187 篇原創文章 · 獲贊 9 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章