hdu 5469 Antonidas (dfs+剪枝)2015 ACM/ICPC Asia Regional Shanghai Online
题意:
给出一棵树,再给出每个节点上的值(一个char字符)这些值以一个字符串s1表示,然后给出一个s2字符串,问在这棵树上是否存在两个点,从一个点走到另一个点所经过的路径上的char字符组成的字符串正好等于s1。问是否存在这么两个点。如果存在,则输出“Find”,否则,输出“Important”。
题解:
使用dfs就可以解决,但是需要进行剪枝,否则就会tle。
剪枝的方法是这样的——假设节点1是根节点,然后我们先使用一次dfs记录每个节点到叶节点的最长的路径dis[x]。
然后开始搜索,每次搜到当前点x的dis[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\n"); 109 else printf("Impossible\n"); 110 } 111 return 0; 112 }