hdu 5469 Antonidas (dfs+剪枝)2015 ACM/ICPC Asia Regional Shanghai Online

题意:

给出一棵树,再给出每个节点上的值(一个char字符)这些值以一个字符串s1表示,然后给出一个s2字符串,问在这棵树上是否存在两个点,从一个点走到另一个点所经过的路径上的char字符组成的字符串正好等于s1。问是否存在这么两个点。如果存在,则输出“Find”,否则,输出“Important”。

 

题解:

使用dfs就可以解决,但是需要进行剪枝,否则就会tle

剪枝的方法是这样的——假设节点1是根节点,然后我们先使用一次dfs记录每个节点到叶节点的最长的路径dis[x]

然后开始搜索,每次搜到当前点xdis[x],如果dis[x]>剩下的字符串s1的值,那么可以走这条路,否则就不走这条路,看这个点的父节点是否满足。

上面那句话可能有些难以理解,具体来讲就是这个意思——如果从当前节点ch向它的叶节点走,需要满足的条件是从点ch到离她最远的叶节点的长度要大于剩余的未匹配的s2串的长度。如果向ch的父节点走,那么就不需要判断了(其实也可以判断,只是要么很麻烦,要么没必要,如果有即简洁又有效的方法,洗耳恭听)。

 

具体见代码:

 

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 const int N = 10010;
  8 
  9 struct Edge
 10 {
 11     int to, next;
 12 }edge[N<<1];        //前向星标,记录邻接表
 13 
 14 int head[N], fm[N];     //节点i的edge[]下标 / 节点i的父节点
 15 int dis[N];             //节点i到最远叶节点的长度
 16 bool vis[N];
 17 int n, t, k;
 18 int len;
 19 char s1[N], s2[N];      //源串与匹配串
 20 
 21 void add(int u, int v)
 22 {
 23     edge[k].to = v;
 24     edge[k].next = head[u];
 25     head[u] = k++;
 26 }
 27 
 28 void tdfs(int x)
 29 {
 30     int mdis = -1;
 31     for(int i = head[x]; i != -1; i = edge[i].next)
 32     {
 33         int v = edge[i].to;
 34         if(!vis[v])
 35         {
 36             vis[v] = 1;
 37             tdfs(v);
 38             fm[v] = x;
 39             mdis = mdis > dis[v] ? mdis : dis[v];
 40         }
 41     }
 42     dis[x] = mdis == -1 ? 1 : mdis+1;       //记录每个节点到最远的叶节点的长度
 43 }
 44 
 45 bool dfs(int x, int disx, int mlen)         //核心dfs
 46 {
 47     if(disx-1 > len) return 1;              //如果已匹配的长度已超过匹配串长度,即,存在这么一个串,及时返回1
 48     if(dis[x] > mlen)                       //如果向叶节点走路径长度大于剩下未匹配的串的长度,则向这个方向走
 49     {
 50         for(int i = head[x]; i != -1; i = edge[i].next)
 51         {
 52             int v = edge[i].to;
 53             if(!vis[v] && s1[v] == s2[disx])
 54             {
 55                 vis[v] = 1;
 56                 if(dfs(v, disx+1, mlen-1)) return 1;
 57             }
 58         }
 59     }
 60     if(!vis[fm[x]] && s1[fm[x]] == s2[disx])    //向父节点搜索
 61     {
 62         vis[fm[x]] = 1;
 63         return dfs(fm[x], disx+1, mlen-1);
 64     }
 65     return 0;                                   //都不存在,则返回0
 66 }
 67 
 68 void init()
 69 {
 70     scanf("%d", &n);
 71     k = 0;
 72     memset(head, -1, sizeof(head));
 73     for(int i = 0; i < n; i++)
 74     {
 75         int a, b;
 76         scanf("%d%d", &a, &b);
 77         add(a, b);
 78         add(b, a);
 79     }
 80     memset(dis, 0, sizeof(dis));
 81     memset(vis, 0, sizeof(vis));
 82     tdfs(1);
 83     scanf("%s%s", s1+1, s2+1);
 84     len = strlen(s2+1)-1;
 85 }
 86 
 87 int main()
 88 {
 89     //freopen("test.in", "r", stdin);
 90     scanf("%d", &t);
 91     for(int tm = 1; tm <= t; tm++)
 92     {
 93         init();
 94         bool flag = 0;
 95         for(int i = 1; i <= n; i++)
 96         {
 97             if(s1[i] == s2[1])
 98             {
 99                 memset(vis, 0, sizeof(vis));
100                 if(dfs(i, 2, len))
101                 {
102                     flag = 1;
103                     break;
104                 }
105             }
106         }
107         printf("Case #%d: ", tm);
108         if(flag) printf("Find
");
109         else printf("Impossible
");
110     }
111     return 0;
112 }
View Code

 

原文地址:https://www.cnblogs.com/mypride/p/4847461.html