目录
题目如下:
?中文翻译:
思路
我们可以发现什么:
AC代码如下(带简单的注释)
代码 单独拉出 边界特判(再次强调一下)
题目如下:
Given three strings a, b and c, your mission is to check whether c is the combine string of aaa and bbb. A string c is said to be the combine string of a and b if and only if c can be broken into two subsequences, when you read them as a string, one equals to aaa, and the other equals to bbb. For example, ``adebcf'' is a combine string of ``abc'' and ``def''.
Input
Input file contains several test cases (no more than 20). Process to the end of file. Each test case contains three strings a, b and c (the length of each string is between 1 and 2000).
Output
For each test case, print ``Yes'', if c is a combine string of a and b, otherwise print ``No''.
Sample
Input | Output |
---|
abc def adebcf abc def abecdf |
Yes No |
?中文翻译:
给定三个字符串a、b和c,你的任务是检查c是否是a和b的组合字符串。 字符串c被称为a和b的组合字符串,当且仅当c可以被分解为两个子序列时,当你将它们作为字符串读取时,一个等于a,另一个等于b。 例如,“adebcf”是“abc”和“def”的组合字符串。
输入文件包含几个测试用例(不超过20个)。处理到文件末尾。 每个测试用例包含三个字符串a、b和c(每个字符串的长度在1到2000之间)。
对于每个测试用例,如果c是a和b的组合字符串,则打印“是”,否则打印“否”。
思路
我们可以把a串所有元素拆开,然后按相对位置关系固定起来,再把b串所有元素拆开按相对位置关系插入进去
如果不好理解,我直接上图帮助大家理解这个思路 (:? Q^Q
读者大大们可以多弄几个,理解一下这个思想!!!
我们可以发现什么:
如果可以满足题意(c串切成两个子串,两个子串正好分别等于a串,b串)
从左到右依次匹配a,b串,一定可以匹配成功的
证明:
我们可以结合上面,按相对位置关系固定a串元素,将b串元素按相对位置关系插入到里面 这个思想去证明!
简单来说(用人话来说):如果可以满足题意,c串一定是可以按照上面的方式构造出来,我们按照上面方式依次匹配,如果可以匹配完成则是Yes,否则是No。
似乎上面说的是很好,但是聪明的你会发现
如果是:
a:ab
b:ba
c:abab
a串先匹配一个后变成下面情况:
a:b
b:ba
c:bab
不难发现,a串与b串都可以匹配c串的b
那怎么办?
如果存在歧义(两串都可以匹配到),我们就接着往下看(看之后的匹配状态)
b串的a可以匹配c串的a并且b串无法匹配成功,那我们就解决了上面的歧义,我们可以把c串的b给b串
这样做一定是正确的嘛?
下面是简单的证明:
因为我们要保证a与b串自身的相对位置关系,所以我们解决 歧义 要在 相对位置关系的保持不变的前提下进行解决,这恰恰就是这个题的核心 & 操纵正确性的证明
举个例子:
如果c串的b给a串,a已完全匹配成功,c串剩下ab,b串剩下ba,发现b串已经无法匹配c串,但这个样例明明是Yes啊(可以完全匹配成功),这是因为我们已经破环了a与b串自身的相对位置关系了。
ps:可能讲的有点模糊,自身水平有限,希望您可以多看几遍思想,按这个思想多模拟几个样例,我想聪明的读者应该可以粗略的理解这个思想的可行性与正确性!
(:(:(:
还有一点需要特别注意欧!!!
一定要特别注意一下边界问题
类似:
a:aaaa
b:aaaa
c:aaaaaaaa
因为一直存在歧义,如果都匹配到头还是存在歧义的话,那就随便让一个串匹配就好啦!
AC代码如下(带简单的注释)
#include <bits/stdc++.h>
#define buff \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0)
using namespace std;
const int N = 2009;
char a[N], b[N], c[N], d[N];
int na, nb, nc;
bool flag;
int main()
{
buff;
while (cin >> a)
{
cin >> b;
cin >> c;
flag = 1;
na = strlen(a);
nb = strlen(b);
nc = strlen(c);
if (nc != (na + nb))
{
puts("No");
continue;
}
int i = 0, j = 0;
for (int k = 0; k < nc; k++)
{
if (a[i] == c[k] && b[j] != c[k])//a可以匹配上(无分歧)
i++;
else if (a[i] != c[k] && b[j] == c[k])//b可以匹配上(无分歧)
j++;
else if (a[i] != c[k] && b[j] != c[k])//a,b都匹配不上,匹配直接失败
{
flag = 0;
break;
}
else//a,b都匹配上,出现分歧(不知道到底让谁匹配,开始进行讨论)
{
int x = i + 1, y = j + 1;
int ok = 0;//无答案(匹配失败)
int z = k + 1;
while (1)
{
//辅助作用
// //----------下面是边界特判
// if(z==nc)
// break;
// if (x == na && y == nb)//匹配到头还是有歧义,那就随便让一个串匹配成功
// {
// ok = 1;
// break;
// }
// else if (x == na && y != nb)//就剩b可以匹配
// {
// ok = 2;
// break;
// }
// else if (y == nb && x != na)//就剩a可以匹配
// {
// ok = 1;
// break;
// }
// //-----------上面是边界特判
if (a[x] == c[z] && b[y] != c[z])//a匹配成功&b匹配失败,歧义解决
{
ok = 1; // a匹配
break;
}
else if (a[x] != c[z] && b[y] == c[z])//b匹配成功&a匹配失败,歧义解决
{
ok = 2; // b匹配
break;
}
else if (a[x] != c[z] && b[y] != c[z])//没有匹配成功但c没有匹配完,匹配接着进行
{
z++;
continue;
}
else//还是存在歧义,再往后看,看是否可以解决这个歧义
{
x++, y++, z++;
}
}
if (ok == 0)//匹配失败
{
flag = 0;
break;
}
else if (ok == 1)//a匹配
{
i++;
}
else//b匹配
{
j++;
}
}
}
if (flag)
puts("Yes");
else
puts("No");
}
}
代码 单独拉出 边界特判(再次强调一下)
if (a[x] == c[z] && b[y] != c[z]) // a匹配成功&b匹配失败,歧义解决
{
ok = 1; // a匹配
break;
}
else if (a[x] != c[z] && b[y] == c[z]) // b匹配成功&a匹配失败,歧义解决
{
ok = 2; // b匹配
break;
}
else if (a[x] != c[z] && b[y] != c[z]) //没有匹配成功但c没有匹配完,匹配接着进行
{
z++;
continue;
}
else //还是存在歧义,再往后看,看是否可以解决这个歧义
{
x++, y++, z++;
}
?我们一路奋战,不是为了改变世界,而是为了不让世界改变我们。——《熔炉》
最后感谢您的阅读!!!
|