Hdu 6170 Two strings【思维+Dp】

351 篇文章 2 订阅

Two strings

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
Giving two strings and you should judge if they are matched.
The first string contains lowercase letters and uppercase letters.
The second string contains lowercase letters, uppercase letters, and special symbols: “.” and “*”.
. can match any letter, and * means the front character can appear any times. For example, “a.b” can match “acb” or “abb”, “a*” can match “a”, “aa” and even empty string. ( “*” will not appear in the front of the string, and there will not be two consecutive “*”.
 

Input
The first line contains an integer T implying the number of test cases. (T≤15)
For each test case, there are two lines implying the two strings (The length of the two strings is less than 2500).
 

Output
For each test case, print “yes” if the two strings are matched, otherwise print “no”.
 

Sample Input
  
  
3 aa a* abb a.* abb aab
 

Sample Output
  
  
yes yes no

题目大意:


给出两个字符串,第一个字符串只包含小写或者大写字母,第二个字符串包含小写或者大写字母或者特殊字符“.”和“*”,这里“.”可以替换为任意字符,但是不能变成空。

这里“a*”可以变成空串,可以变成a,也可以是aa,也可以是aaa,还可以是aaaa.以此类推,不限长度。

问第二个串和第一个串是否能够完全相等。


思路:


观察到数据范围,如果是贪心做法的话,数据范围肯定不能这么小,而且仔细考虑一下,直接贪心O(n)扫显然有纰漏;

那么我们考虑Dp,设定Dp【i】【j】表示串2到位子i,实际匹配串1到位子j的方案是否存在。


那么不难想到其状态转移方程:


①if(b[i]是大写字母或者是小写字母)Dp【i】【j】=Dp【i-1】【j-1】&&(a【i】==a【j】);

②if(b[i]是“.”)Dp【i】【j】=Dp【i-1】【j-1】;

③if(b[i]是“*”):

Dp【i】【j】=max(Dp【i-1】【j】,Dp【i】【j】);

Dp【i】【j】=max(Dp【i-2】【j】,Dp【i】【j】);

Dp【i】【j】=max(Dp【i-1】【k~j-1】,Dp【i】【j】);位子k到位子j-1之间的字符要保证都相等。


我们发现暴力去搞的话时间复杂度最坏可以达到O(n^3),那么我们考虑优化,很显然位子k是可以进行二分的,但是时间复杂度还是O(n^2logn)依然不低,但是我们可以维护一个数组pre【j】,表示和a【j】相等的字符串的最前边的位子,也就是我们的k,可以在Dp的过程维护,那么我们只要再求一个Dp的前缀和优化一下就能够达到O(n)了;那么状态转移方程③可以进行优化为:


Dp【i】【j】=max(Sum【i-1】【j-1】-Sum【i-1】,Dp【i】【j】);位子k到位子j-1之间的字符要保证都相等。


注意初始化,就没有别的什么了。


Ac代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
char a[2600];
char b[2600];
bool dp[2600][2600];
int pre[2600];
int Is_or[2600][2600];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",a+1);
        scanf("%s",b+1);
        int n=strlen(a+1);
        int m=strlen(b+1);
        memset(dp,false,sizeof(dp));
        dp[0][0]=true;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<=n;j++)
            {
                if(j==1)pre[j]=j;
                else
                {
                    if(a[j]==a[j-1])pre[j]=pre[j-1];
                    else pre[j]=j;
                }
                if(b[i]=='.')
                {
                    if(j-1>=0)dp[i][j]=dp[i-1][j-1];
                }
                else if(b[i]=='*')
                {
                    if(j==0)dp[i][j]=dp[i-1][j];
                    else
                    {
                        int pos=pre[j];
                        int tmp;
                        if(Is_or[i-1][j-1]-Is_or[i-1][pos-1]>0)tmp=1;
                        else tmp=0;
                        dp[i][j]=tmp;
                    }
                    if(i-1>=0)dp[i][j]=max(dp[i][j],dp[i-1][j]);
                    if(i-2>=0)dp[i][j]=max(dp[i][j],dp[i-2][j]);
                }
                else
                {
                    if(j-1>=0)dp[i][j]=(dp[i-1][j-1])&&(b[i]==a[j]);
                }
                if(j==0)Is_or[i][j]=dp[i][j];
                else Is_or[i][j]=dp[i][j]+Is_or[i][j-1];
            }
        }
        if(dp[m][n]==true)printf("yes\n");
        else printf("no\n");
    }
}





  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值