题意:输入三个字符串,前两个随意交错排列看能不能形成第三个
思路:本题有缺陷,就是测试数据弱爆了,所以直接暴力深搜加几个特解就能过,不过暴力深搜的就没给代码了,直接是平常深搜的代码,然后是DP的代码,解释在代码中
深搜:
#include <iostream> #include <cstring> using namespace std; char s1[222],s2[222],s3[444]; int l1,l2,visit[222][222]; bool dfs(int i,int j,int k) { if(k==l1+l2)return 1;//s3的下标等于s1加s2长度的时候就表示搜完了 if(visit[i][j])return 0;//这一步很重要,没了他就超时,深搜讲究的就是不重复搜同一个点 visit[i][j]=1; if(i<l1&&s1[i]==s3[k]&&dfs(i+1,j,k+1))return 1;//s1能和s3匹配就递归一次,返回值为1就接着返回,因为返回1表示的就是找到了对的路了 if(j<l2&&s2[j]==s3[k]&&dfs(i,j+1,k+1))return 1;//s2能和s3匹配也递归一次 return 0; } int main (void) { int n,i,j,k=1; cin>>n; while(n--&&cin>>s1>>s2>>s3) { l1=strlen(s1); l2=strlen(s2); for(i=0;i<222;i++)//初始化标记数组 for(j=0;j<222;j++) visit[i][j]=0; cout<<"Data set "<<k++<<": "; if(dfs(0,0,0))cout<<"yes"<<endl;//直接从三个字符串的第一个开始深搜 else cout<<"no"<<endl; } return 0; }
DP://DP的想法就是DP[i][j]代表s1[i]和s2[j]这两个点同ss[i+j]匹配的当前状态
如匹配catrtee,不看其他杂乱的最终就得到这样个图(实际上还有些数字,因为可能是从中间开始匹配成功的)
c a t
0 1 2 0
t 0 0 3 0
r 0 0 4 5
e 0 0 0 6
e 0 0 0 7
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int l1,l2,l3; char s1[444],s2[444],ss[444]; int main (void) { int i,j,n,m=1,dp[222][222]; scanf("%d",&n); while(n--&&scanf("%s%s%s",s1,s2,ss)) { memset(dp,0,sizeof(dp)); l1=strlen(s1); l2=strlen(s2); l3=strlen(ss); if(ss[0]==s1[0])dp[1][0]=1;//如果s1第一个和ss配上就标记初始状态“s1成功一个,s2成功0个”为1
if(ss[0]==s2[0])dp[0][1]=1;//同上 for(i=0;i<=l1;i++)//有了初始状态之后就进行下面的递归 for(j=0;j<=l2;j++) { if(i>0&&s1[i-1]==ss[i+j-1])//s1没完,就用s1来匹配 dp[i][j]=max(dp[i][j],dp[i-1][j]+1);//取当前点的值与由前一个状态递推过来的值的最大值,因为有的从中间开始匹配成功的树值会干扰结果 if(j>0&&s2[j-1]==ss[i+j-1]) dp[i][j]=max(dp[i][j],dp[i][j-1]+1); } printf("Data set %d: ",m++); if(dp[l1][l2]==l3) cout<<"yes"<<endl; else cout<<"no"<<endl; } return 0; }