ZOJ - 1379 Wild Domains dp

题目链接

题意:t组数据,给出两个字符串,对于每个字符串的每个子字符串通过"."隔开。有三个特殊作用的字符"?","*","!",求按照匹配规则,两个字符串是否匹配。

思路:一开始硬肝dp一直wa,所以由于这三个字符的特殊作用,我们应该简化一下三个字符,我们可以重新定义!:匹配一个,*作用不变,?:匹配一个或者不匹配。这样原来的*仍然是*,?变为!??,!变为!!*。这样对于dp[i][j]是否有解只需要看dp[i-1][j-1],dp[i][j-1],dp[i-1][j]其中几个的状态就行了。(dp[i][j],表示到第一个字符串的第i个字符串,第二个字符串的第j个子字符串为止,两字符串是否匹配)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define PI acos(-1)
#define INF 0x3f3f3f3f
#define NUM 256
#define debug true
#define ll long long
#define lowbit(x) ((-x)&x)
#define ffor(i,d,u) for(int i=d;i<=u;++i)
#define _ffor(i,u,d) for(int i=u;i>=d;--i)
#define mst(array,Num) memset(array,Num,sizeof(array))
const int p = 1e9+7;
char a[NUM],b[NUM];
bool dp[NUM][NUM];
int linka[NUM],linkb[NUM];
int l1,l2,ls1,ls2;
string s1,s2;
template <typename T>
void read(T& x)
{
    x=0;
    char c;T t=1;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c=='-'){t=-1;c=getchar();}
    do(x*=10)+=(c-'0');while((c=getchar())>='0'&&c<='9');
    x*=t;
}
template <typename T>
void write(T x)
{
    int len=0;char c[21];
    if(x<0)putchar('-'),x*=(-1);
    do{++len;c[len]=(x%10)+'0';}while(x/=10);
    _ffor(i,len,1)putchar(c[i]);
}
void tryya(const int& pos)//重新定义!:匹配一个,*不变,?:匹配一个或者不匹配
{
    if(a[l1]=='*')
        return ;
    if(a[l1]=='!')
    {
        a[++l1]='!';
        a[++l1]='*';
        return ;
    }
    if(a[l1]=='?')
    {
        a[l1]='!';
        a[++l1]='?';
        a[++l1]='?';
        return ;
    }
    linka[l1]=pos;
}
void tryyb(const int& pos)//重新定义!:匹配一个,*不变,?:匹配一个或者不匹配
{
    if(b[l2]=='*')
        return ;
    if(b[l2]=='!')
    {
        b[++l2]='!';
        b[++l2]='*';
        return ;
    }
    if(b[l2]=='?')
    {
        b[l2]='!';
        b[++l2]='?';
        b[++l2]='?';
        return ;
    }
    linkb[l2]=pos;
}
void solve()
{
    int k1,k2;bool flag;
    dp[0][0]=true;
    ffor(i,1,l1)if(a[i]=='?'&&dp[i-1][0])dp[i][0]=true;
    ffor(i,1,l2)if(b[i]=='?'&&dp[0][i-1])dp[0][i]=true;
    ffor(i,1,l1)
        ffor(j,1,l2)
        {
            flag=false;
            if(a[i]=='*'||b[j]=='*')
            {
                if(a[i]=='*'&&(dp[i][j-1]||dp[i-1][j-1]))dp[i][j]=true;
                if(b[j]=='*'&&(dp[i-1][j]||dp[i-1][j-1]))dp[i][j]=true;
                flag=true;
            }
            if(a[i]=='!'||b[j]=='!')
            {
                if(dp[i-1][j-1])
                    dp[i][j]=true;
                flag=true;
            }
            if(a[i]=='?'||b[j]=='?')
            {
                if(a[i]=='?'&&(dp[i-1][j-1]||dp[i-1][j]))dp[i][j]=true;
                if(b[j]=='?'&&(dp[i-1][j-1]||dp[i][j-1]))dp[i][j]=true;
                flag=true;
            }
            if(flag||!dp[i-1][j-1])continue;
            k1=linka[i],k2=linkb[j];
            flag=true;
            while(k1<=ls1&&k2<=ls2&&s1[k1]!='.'&&s2[k2]!='.')
            {
                if(s1[k1]!=s2[k2])
                {
                    flag=false;
                    break ;
                }
                ++k1,++k2;
            }
            dp[i][j]=((k1>ls1||s1[k1]=='.')&&(k2>ls2||s2[k2]=='.')&&flag);
        }
    if(dp[l1][l2])
        puts("YES");
    else
        puts("NO");
}
void AC()
{
    int T;
    read(T);
    while(T--)
    {
        cin>>s1>>s2;
        a[1]=s1[0];b[1]=s2[0];
        l1=l2=1;
        tryya(0);tryyb(0);
        mst(dp,false);
        ls1=s1.size()-1;
        ffor(i,1,ls1)if(s1[i]=='.'){a[++l1]=s1[i+1];tryya(i+1);}
        ls2=s2.size()-1;
        ffor(i,1,ls2)if(s2[i]=='.'){b[++l2]=s2[i+1];tryyb(i+1);}
        solve();
    }
}
int main()
{
    AC();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值