sicily 1010. Zipper dfs || dp
//这题可以用暴力搜索 //要注意减枝和各种预处理,不然各种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; }