题意:
n个点的一颗树,每一个点代表一个字符,给你一个字符串,问你能否有一个A,B,使得A->B的最短路径是该字符串表示的。
解析:
看到这道题,一开始就想到DFS,但会T,因为这里N<=1e4,而字符只有26个小写的英文字母,所以会有两个点表示相同的字母。因此需要你用深度来剪枝。先随便以一个点(这里是1)作为根DFS整棵树,求出他们的深度。再遍历给你的表示他们结点的字符串,如果这个点的字符=目标串的第一个字符,那么就以这个点为根进行DFS搜索。剪枝就是,如果这个点下面的深度不可能满足剩余目标串的条件,就不需要继续往下搜了。注意因为我们求深度是按照1来计算的,所以这里需要记录他原来的父节点来求某些节点的对于当前根的深度。
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN = 1e4+100;
vector<int> edg[MAXN];
char art[MAXN];
char path[MAXN];
int pre[MAXN];
int dep[MAXN],len,n;
void dfs_dep(int u,int fa)
{
dep[u]=1;
for(int i=0;i<edg[u].size();i++)
{
int v=edg[u][i];
if(v!=fa)
{
pre[v]=u;
dfs_dep(v,u);
dep[u]=max(dep[v]+1,dep[u]);
}
}
}
int dfs_find(int u,int fa,int ds)
{
if(ds==len) return true;
for(int i=0;i<edg[u].size();i++)
{
int v=edg[u][i];
if(v!=fa&&art[v-1]==path[ds])
{
if(pre[v]==u&&len-ds<=dep[v])
{
if(dfs_find(v,u,ds+1)) return true;
}
else if(pre[v]!=u&&n-dep[v]>=len-1-ds)
{
if(dfs_find(v,u,ds+1)) return true;
}
}
}
return false;
}
int main()
{
int t;
int ncount=0;
scanf("%d",&t);
while(t--)
{
ncount++;
memset(pre,-1,sizeof(pre));
scanf("%d",&n);
int a,b;
for(int i=1;i<=n;i++) edg[i].clear();
for(int i=0;i<n;i++)
{
scanf("%d%d",&a,&b);
edg[a].push_back(b);
edg[b].push_back(a);
}
scanf("%s",art);
//dfs_dep(1,-1);
scanf("%s",path);
len=strlen(path);
dfs_dep(1,-1);
bool tmp=false;
for(int i=0;art[i];i++)
{
if(art[i]==path[0])
{
tmp=dfs_find(i+1,-1,1);
}
if(tmp) break;
}
printf("Case #%d: ",ncount);
if(tmp) printf("Find\n");
else printf("Impossible\n");
}
return 0;
}