hdu 5311 Hidden String dp o(n)算法 深搜

来源:互联网 发布:表情制作软件 编辑:程序博客网 时间:2024/05/18 16:14

Hidden String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 857    Accepted Submission(s): 322


Problem Description
Today is the 1st anniversary of BestCoder. Soda, the contest manager, gets a strings of length n. He wants to find three nonoverlapping substrings s[l1..r1],s[l2..r2],s[l3..r3] that:

1. 1l1r1<l2r2<l3r3n

2. The concatenation of s[l1..r1],s[l2..r2],s[l3..r3] is "anniversary".
 

Input
There are multiple test cases. The first line of input contains an integerT(1T100), indicating the number of test cases. For each test case:

There's a line containing a string s(1|s|100) consisting of lowercase English letters.
 

Output
For each test case, output "YES" (without the quotes) if Soda can find such thress substrings, otherwise output "NO" (without the quotes).
 

Sample Input
2annivddfdersewwefarynniversarya
 

题意,就是给一段字符串,要求找出目标串,且最多只能三个片段串。

由于s很小,所以用深搜,暴力乱搞就好了。但这里用dp也能解决。复杂度是o(n)

定义pre[i][j] 表示字符串第i个位置,从目标串往后能匹配pre[i][j] 个,也就是说s(i,i+pre[i][j] ) == g(j,j+pre[i][j] ) g表示目标串。

则pre[i][j] 转状转移很简单就是pre[i+1][j+1]转移来就可以了。

定义dp[i][j]表示,字符串第i-1个位置前已经匹配到了目标串g的第j-1个位置且已用的分段数就是dp[i][j]。则状态转移方程就是

dp[i][j]可以从dp[i-1][j]得来,也可以转移到dp[i+pre[i][j]][j+pre[i][j]],取分段数的最小值。

答案只要dp[s][11]大于1,说明存在。

由于本题目标串g的长度为定值,所以复杂度为o(s * 11)线性算法,如果,改变一下,g不是字长,而是变长的,那么复杂度则为o(s* g)了,与分段数是无关的。

#define N 205#define M 100005#define maxn 205#define MOD 1000000000000000007int n,glen,len,dp[N][12],pre[N][11];char str[N];char goal[20] = "anniversary";void Update(int & a,int b){    if(a == 0) a = b;    else a = min(a,b);}int main(){    glen = strlen(goal);    while(S(n)!=EOF)    {        while(n--){            SS(str);len = strlen(str);            FI(len){                FJ(11){                    if(str[i] == goal[j]) pre[i][j] = 1;                    else pre[i][j] = 0;                }            }            for(int i = len - 2;i>=0;i--){                FJ(10){                    if(pre[i][j] && pre[i+1][j+1]) pre[i][j] = pre[i+1][j+1] + 1;                }            }            fill(dp,0);            for(int i = 0;i<len;i++){                FJ(11){                    if(i && dp[i-1][j])   Update(dp[i][j],dp[i-1][j]);                    if((dp[i][j] || !j )&&dp[i][j] < 3 && pre[i][j]){                     Update(dp[i+pre[i][j]][j+pre[i][j]],dp[i][j] + 1);                    }                }            }            bool flag = true;            for(int i = 0;i<=len && flag;i++){                if(dp[i][11]) flag = false;            }            if(!flag)                printf("YES\n");            else                printf("NO\n");        }    }    return 0;}

再给个用深搜暴力解决的,更简单,更好理解,也好写,在比赛的时候,抢时间,也能有用处,但复杂度就很高了。

#define N 205#define M 100005#define maxn 205#define MOD 1000000000000000007int n,glen,len;char str[N];char goal[20] = "anniversary";bool DFS(int si,int gi,int num){    if(num <=3 && gi >= glen) return true;    if(num > 3) return false;    for(int i = si;i<len;i++){        int ti = i,tgi = gi;        while(ti<len && tgi < glen && str[ti] == goal[tgi]) tgi++,ti++;        if(ti > i && DFS(ti,tgi,num + 1)) return true;    }    return false;}int main(){    glen = strlen(goal);    while(S(n)!=EOF)    {        while(n--){            SS(str);len = strlen(str);            if(DFS(0,0,0))            printf("YES\n");            else            printf("NO\n");        }    }    return 0;}


Sample Output
YESNO
 

Source
BestCoder 1st Anniversary ($)
 

Recommend
hujie   |   We have carefully selected several similar problems for you:  5315 5314 5312 5310 5309 
0 0
原创粉丝点击