//这题可以用暴力搜索
//要注意减枝和各种预处理,不然各种TLE
//方法是搜索s里的=s1的子串,再判断s剩下的字符是否能组成s2
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 205;
char s1[N], s2[N], s[N], tmp[N];
int low_times1[30], low_times2[30], upper_times1[30], upper_times2[30];
int s1_size, s2_size, s_size;
int flag[N+N];
//dfs查找s串里的等于s1的子串
//剩下的按顺序就是s2串
bool dfs(int s1_count,int count)
{
if (s1_count > s1_size)
return false;
int cnt = 0;
//找出s1串,判断剩下的是否能组成s2串
if (s1_count == s1_size)
{
cnt = count-s1_count;
for (int i = count; i < s_size; i++)
if (flag[i] == 0)
{
if (s[i] != s2[cnt])
return false;
cnt++;
}
return true;
}
//若s1相邻两个字符所在s的位置为i和j,那么s的i~j之间的组成的字串必须是s2的字串
//根据这个条件减枝
for (int i = 0; i < count; i++)
if (flag[i] == 0)
{
if (s[i] != s2[cnt])
return false;
cnt++;
}
for (int i = count; i < s_size; i++)
if (s1[s1_count] == s[i])
{
flag[i] = 1;
if (dfs(s1_count+1, i+1))
return true;
flag[i] = 0;
}
return false;
}
int main()
{
int cases;
int num = 0;
scanf("%d", &cases);
while (cases--)
{
num++;
memset(flag, 0, sizeof(flag));
memset(low_times1, 0, sizeof(low_times1));
memset(upper_times2, 0, sizeof(upper_times2));
memset(upper_times1, 0, sizeof(upper_times1));
memset(low_times2, 0, sizeof(low_times1));
scanf("%s%s%s", s1, s2, s);
s1_size = strlen(s1);
s2_size = strlen(s2);
s_size = s1_size + s2_size;
if (s1_size > s2_size)
{
strcpy(tmp, s1);
strcpy(s1, s2);
strcpy(s2, tmp);
swap(s1_size, s2_size);
}
for (int i = 0; i < s1_size; i++)
if (s1[i] >= 'a' && s1[i] <= 'z')
low_times1[s1[i]-'a']++;
else
upper_times1[s1[i] - 'A']++;
for (int i = 0; i < s2_size; i++)
if (s2[i] >= 'a' && s2[i] <= 'z')
low_times1[s2[i]-'a']++;
else
upper_times1[s2[i]-'A']++;
for (int i = 0; i < s_size; i++)
if (s[i] >= 'a' && s[i] <= 'z')
low_times2[s[i]-'a']++;
else
upper_times2[s[i] - 'A']++;
//先预处理
//s的字符出现个数应 = s1字符出现个数+s2字符个数
bool ans = true;
for (int i = 0; i < 26; i++)
if (low_times1[i] != low_times2[i] || upper_times1[i] != upper_times2[i])
{
ans = false;
break;
}
if (!ans)
{
printf("Data set %d: no\n", num);
continue;
}
if (dfs(0, 0))
printf("Data set %d: yes\n", num);
else
printf("Data set %d: no\n", num);
}
return 0;
}
//后来发现原来可以直接dp
//设dp[i][j]为a串的前i个字符和b串的前j个字符能否组成c的i+j个字符
//dp[i][j] = (dp[i-1][j] && c[i+j] == a[i]) || (dp[i][j-1] && c[i+j] = b[j])
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
const int N = 205;
string a, b, c;
bool dp[N][N];
int main()
{
int cases;
int num = 0;
cin >> cases;
while (cases--)
{
num++;
cin >> a >> b >> c;
memset(dp, false, sizeof(dp));
dp[0][0] = true;
for (int i = 0; i < b.size(); i++)
if (b[i] == c[i])
dp[0][i+1] = true;
else
break;
for (int i = 0; i < a.size(); i++)
if (a[i] == c[i])
dp[i+1][0] = true;
else
break;
for (int i = 1; i <= a.size(); i++)
for (int j = 1; j <= b.size(); j++)
dp[i][j] = (dp[i-1][j] && c[i+j-1] == a[i-1]) || (dp[i][j-1] && c[i+j-1] == b[j-1]);
if (dp[a.size()][b.size()])
cout << "Data set "<< num << ": yes" << endl;
else
cout << "Data set "<< num << ": no" << endl;
}
return 0;
}