题意:
给定三个字符串,如果前两个可以拼装成第三个,则输出yes,否则输出no。
思路:
1:
DFS:
最直观的思路是可以用dfs去搜,从第三个字符串为目标串去dfs(0,0,0)。
如果在第一个串里字符匹配,则dfs(i+1,j,k)。这种dfs本质所在搜一刻二叉树。
但是我觉得这种ac了说明数据弱,否则因为这种dfs需要回溯,很容易超时。
不过ac也是看了discuss里面的一个神奇的剪枝才ac的。
2:
DP:
从dfs深搜的过程中其实就可以发现规律。
我也是在写dfs的过程中想到其实可以用记忆化dp,因为记忆化搜索我的理解就是为了消除回溯的。
dp方程在代码里有解释。
时间复杂度O(N);
挺不错的一道题目,加深了我对记忆化dp的理解。
深搜代码:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int N=405; int len0,len1,len2; char str[4][N]; int dp[N+N]; //dp[i+j]=(str1[i+1] && str2[j]) || (str1[]) bool dfs(int pt0,int pt1,int pt2) { if(pt2>=len2) return true; char a=str[2][pt2]; // printf("%d%d%d%c\n",pt0,pt1,pt2,a); // printf("%c",str[0][pt0]); if(pt0<len0&&str[0][pt0]==a) { if(dfs(pt0+1,pt1,pt2+1)) return true; } // printf("%c",str[1][pt1]); if(pt1<len1&&str[1][pt1]==a) { if(dfs(pt0,pt1+1,pt2+1)) return true; } // printf("%d%d%d%c\n",pt0,pt1,pt2,a); return false; } void solve() { if(dfs(0,0,0)) printf("yes\n"); else printf("no\n"); } int main() { //freopen("1.txt","r",stdin); int T; scanf("%d",&T); for(int t=1;t<=T;t++) { memset(dp,0,sizeof(dp)); scanf("%s%s%s",str[0],str[1],str[2]); len2=strlen(str[2]); // printf("%s %s %s\n",str[0],str[1],str[2]); len0=strlen(str[0]); len1=strlen(str[1]); if(str[0][len0-1]!=str[2][len2-1]&&str[1][len1-1]!=str[2][len2-1]) { printf("Data set %d: no\n",t); continue; } printf("Data set %d: ",t); solve(); } return 0; }
dp代码:
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int N=405; int len0,len1,len2; char str[4][N]; bool dp[N][N/2]; //dp[k][i]: //1:代表第三个字符串的第k个字符由第一个字符串的前i个字符和第二个字符从的前k-i个字符构成。 //0:代表第三个字符串的第k个字符由第一个字符串的前i个字符和第二个字符从的前k-i个字符无法构成。 bool solve() { if(str[0][1]==str[2][1]) dp[1][1]=true; if(str[1][1]==str[2][1]) dp[1][0]=true; for(int k=1;k<len2;k++) { int flag=0; for(int i=0;i<=k;i++) { int j=k-i; if(dp[k][i]) { flag=1; if(str[0][i+1]==str[2][k+1]) { dp[k+1][i+1]=true; } if(str[1][j+1]==str[2][k+1]) { dp[k+1][i]=true; } } } if(!flag) return false; } bool ans=false; for(int i=0;i<len2;i++) { if(dp[len2][i]) { ans=true; break; } } return ans; } int main() { int T; scanf("%d",&T); for(int t=1;t<=T;t++) { memset(dp,0,sizeof(dp)); scanf("%s%s%s",str[0]+1,str[1]+1,str[2]+1); len2=strlen(str[2]+1); len0=strlen(str[0]+1); len1=strlen(str[1]+1); printf("Data set %d: ",t); if(solve()) printf("yes\n"); else printf("no\n"); } return 0; }
人生第一次在linux下vim编辑器写的代码,用惯了vs 的人表示gdb调试得想哭,后来索性就放弃gdb了,直接靠printf来调试,泪流满面。