Codeforces Gym100962J:Jimi Hendrix(树型DP)
http://codeforces.com/gym/100962/attachments
题意:有一个n个节点的字母树,给出n-1条边的信息,代表边上有一个字母,然后给出长度为m的字符串,问是否能在这棵树上找到这样一个序列等于这条字符串,输出序列的起点和终点。
思路:用DP数组维护当到达该结点的时候,左边最长的长度是多少和达到这个长度的左端点,右边最长的长度是多少和达到这个长度的右端点。详细看代码,很容易懂。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define N 500010 4 struct Edge { 5 int v, nxt; char c; 6 } edge[N*2]; 7 struct node { 8 int l, r, ansl, ansr; 9 } dp[N]; // l是保存头,r是保存尾的信息 10 int tot, head[N], n, m, ansu, ansv; 11 char s[N]; 12 13 void Add(int u, int v, char c) { 14 edge[tot] = (Edge) {v, head[u], c}; head[u] = tot++; 15 edge[tot] = (Edge) {u, head[v], c}; head[v] = tot++; 16 } 17 18 bool dfs(int u, int fa) { 19 for(int i = head[u]; ~i; i = edge[i].nxt) { 20 int v = edge[i].v; char c = edge[i].c; 21 if(v == fa) continue; 22 if(dfs(v, u)) return true; // 已经有答案了 23 int ltmp = dp[v].l; 24 int rtmp = dp[v].r; 25 if(c == s[dp[v].l]) ltmp++; // 如果当前的边是左边的下一个字符 26 if(c == s[m - dp[v].r - 1]) rtmp++; // 如果当前的边是右边的下一个字符 27 if(ltmp + dp[u].r >= m) { // 有答案了 28 ansu = dp[v].ansl, ansv = dp[u].ansr; 29 return true; 30 } 31 if(dp[u].l + rtmp >= m) { 32 ansu = dp[u].ansl, ansv = dp[v].ansr; 33 return true; 34 } 35 if(ltmp > dp[u].l) { // 如果长度变长就更新 36 dp[u].ansl = dp[v].ansl; 37 dp[u].l = ltmp; 38 } 39 if(rtmp > dp[u].r) { 40 dp[u].ansr = dp[v].ansr; 41 dp[u].r = rtmp; 42 } 43 } 44 return false; 45 } 46 47 int main() { 48 scanf("%d%d", &n, &m); 49 tot = 0; memset(head, -1, sizeof(head)); 50 for(int i = 1; i < n; i++) { 51 int u, v; char c; 52 cin >> u >> v >> c; 53 Add(u, v, c); 54 dp[i].l = dp[i].r = 0; // 点的信息 55 dp[i].ansl = dp[i].ansr = i; // 端点答案的信息 56 } 57 dp[n].l = dp[n].r = 0; 58 dp[n].ansl = dp[n].ansr = n; 59 cin >> s; 60 ansu = ansv = -1; 61 dfs(1, -1); 62 printf("%d %d\n", ansu, ansv); 63 return 0; 64 }