题意:
给定三个字符串,如果前两个可以拼装成第三个,则输出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来调试,泪流满面。