poj 2192 Zipper 【DFS+剪枝】

Problem Description

Given three strings, you are to determine whether the third string can be formed by combining the characters in the first two strings. The first two strings can be mixed arbitrarily, but each must stay in its original order.

For example, consider forming "tcraete" from "cat" and "tree":

String A: cat
String B: tree
String C: tcraete


As you can see, we can form the third string by alternating characters from the two strings. As a second example, consider forming "catrtee" from "cat" and "tree":

String A: cat
String B: tree
String C: catrtee


Finally, notice that it is impossible to form "cttaree" from "cat" and "tree".

Input

The first line of input contains a single positive integer from 1 through 1000. It represents the number of data sets to follow. The processing for each data set is identical. The data sets appear on the following lines, one data set per line. For each data set, the line of input consists of three strings, separated by a single space. All strings are composed of upper and lower case letters only. The length of the third string is always the sum of the lengths of the first two strings. The first two strings will have lengths between 1 and 200 characters, inclusive.

Output

For each data set, print: Data set n: yes if the third string can be formed from the first two, or Data set n: no if it cannot. Of course n should be replaced by the data set number. See the sample output below for an example.

Sample Input

 

3 cat tree tcraete cat tree catrtee cat tree cttaree

Sample Output

 

Data set 1: yes Data set 2: yes

Data set 3: no

题目:前两个字符串在不改变循序的情况下,能否组成第三个字符串;

思路:我的代码可能有点乱,这里听下思路就行了,这道题有一个规律,我们这里假设三个字符串为 S1,S2,S3,要想不改变顺序的情况下组合得到S3,那么S3的第一个字符一定是 S1的第一个或者是S2的第一个,也就是说,假设S1的第一个字符是S3第一个字符,那么,S3的第二个字符一定是S1的第二个字符或者是S2的第一个字符,在纸上模拟一下就能明白了,所以问题就很清楚了,但是这里有一个我们要解决的主要问题就是,当能选的两个字符相等的时候,我们应该选S1的那个还是选S2的那个字符,这里的选择是会影响最后的结果的,说到DP,这里就有点像拿与不拿的问题了,不过我的思路就是,当遇到这种选择的时候,dfs两种情况,先拿S1的看看结果如何,如果不行就 return 回来选第二种情况,这里dfs会消耗很多时间,所以,要在每一个确定一定不是答案的情况下,也就是只要在选S1,和S2的那个字符都和S3不相等时就可以直接return了,所以我写的代码有很多renturn,看起来很头疼,这是一个小剪枝,我们还需考虑另外一种,dfs在return回溯的时候,有可能会重复遇到同一种选择,比如说,假设第一个位置有二个选择,我们选第一种,之后到第二个位置有两个选择,我们已经走过了,而且是行不通的,我们就会回到第一个位置然后选第二种选择,但是,走到之前在第一种选择的时候,走过的第二个位置,我们应该直接return,这样可以省下不少时间;用一个二维vis标记一下就行了; 下面代码的时间在poj上是 13ms,挺快的剪枝;

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
#include<string>

using namespace std;

#define Maxn 410
#define INF 0x3f3f3f3f

int vis[205][205];
string a, b, c;
bool ok;

void dfs (int pa, int pb, int pc) {
    int len = c.size(),len_a = a.size(), len_b = b.size();
    for (int i = pc; i < len; ++i) {
        if(pa >= len_a) {
                if(c[i] == b[pb]) pb++;
                else  return;
        }
        else if(pb >= len_b) {
            if(c[i] == a[pa]) pa++;
            else return;
        }
        else {
            if(c[i] != a[pa] && c[i] != b[pb]) return;
            else if(b[pb] == a[pa]) {
                    if(vis[pa][pb]) return;
                    dfs(pa+1, pb, i+1);
                    if(ok) return;
                    dfs(pa, pb+1, i+1);
                    vis[pa][pb] = 1;
                    return;
            }
            else if(a[pa] == c[i]) pa++;
            else if(b[pb] == c[i]) pb++;
        }
    }
    ok = true; return;
}

int main (void)
{
    int N;
    cin >> N;
    for (int t = 1; t <= N; ++t) {
            cin >> a >> b >> c;
            ok = false;
            memset(vis,0,sizeof(vis));
            dfs(0,0,0);
            if(ok) printf("Data set %d: yes\n",t);
            else printf("Data set %d: no\n",t);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/81195028