HDU 5469 Antonidas (树形DP,暴力)
题意:
给一棵n节点的树图,每个点都是一个小写字母,要求找到两个点(a,b),从a->b的路径上形成了一个字符串为s。给出s,问是否存在这样的点对。
思路:
考虑一个点,要么从该点出发,要么在该点结束,要么它作为一个中间点将左右两个串连起来成为s。叶子只能是起点或者终点。在每个点中需要保存两个队列,表示有点可以从正or反向走到这个点的长度(即前缀与后缀,但只需记录当前点是排在第几)。对于在本节点连接的情况,枚举一下哪些孩子可能在本节点连接就行了。
2s多
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 #define pii pair<int,int> 3 #define max(x,y) ((x)>(y)?(x):(y)) 4 #define min(x,y) ((x)<(y)?(x):(y)) 5 #define abs(x) ((x)<0?-(x):(x)) 6 #define INF 0x3f3f3f3f 7 #define LL long long 8 using namespace std; 9 const double PI = acos(-1.0); 10 const int N=10010; 11 struct node 12 { 13 int from, to, next; 14 node(){}; 15 node(int from,int to,int next):from(from),to(to),next(next){}; 16 }edge[N*2]; 17 18 int head[N], edge_cnt, n, m; 19 char c[N], s[N]; 20 void add_node(int from,int to) 21 { 22 edge[edge_cnt]=node(from,to,head[from]); 23 head[from]=edge_cnt++; 24 } 25 26 bitset<10005> mapp[N], mapp2[N]; 27 deque<int> que1[N], que2[N]; 28 bool ans; 29 void DFS(int t,int far) 30 { 31 node e; 32 for(int i=head[t]; i!=-1 && ans==false; i=e.next) 33 { 34 e=edge[i]; 35 if(e.to==far) continue; 36 DFS(e.to, t); 37 38 int siz=que1[e.to].size(); 39 for(int j=0; j<siz; j++) //将que1装进来先 40 { 41 int r=que1[e.to].front(); 42 que1[e.to].pop_front(); 43 que1[e.to].push_back(r); //que1[e.to]并没有删除 44 if( c[t]==s[r+1] ) 45 { 46 if(mapp[t][r+1]) mapp2[t][r+1]=1; //增加1个位表示是否有两个孩子能连到此点 47 else if(!mapp[t][r+1]) mapp[t][r+1]=1,que1[t].push_back(r+1); 48 if(r+1==m) 49 { 50 ans=true; 51 return ; 52 } 53 } 54 } 55 } 56 57 for(int i=head[t]; i!=-1 && ans==false; i=e.next) //考虑每个孩子 58 { 59 e=edge[i];if(e.to==far) continue; 60 61 int siz=que1[e.to].size(); //先把此孩子的左,从mapp中全部去掉 62 for(int j=0; j<siz; j++) 63 { 64 int r=que1[e.to].front(); 65 que1[e.to].pop_front(); 66 que1[e.to].push_back(r); 67 if( c[t]==s[r+1] && !mapp2[t][r+1] ) mapp[t][r+1]=0; 68 } 69 70 siz=que2[e.to].size(); //判断是否在此点链接 71 for(int i=0; i<siz; i++) 72 { 73 int r=que2[e.to].front(); 74 que2[e.to].pop_front(); 75 que2[e.to].push_back(r); //que2还没有删 76 if( mapp[t][r-1]==1 ){ ans=true; return ;} //找到了另一半 77 } 78 79 while( !que2[e.to].empty() ) //找不到时,再将que2装进去 80 { 81 int r=que2[e.to].front();que2[e.to].pop_front(); 82 if( c[t]==s[r-1] ) //刚好相同 83 { 84 que2[t].push_back( r-1 ); 85 if(r-1==1) //以此点为终点 86 { 87 ans=true; 88 return ; 89 } 90 } 91 } 92 93 while( !que1[e.to].empty() ) //将此孩子的que1装回去 94 { 95 int r=que1[e.to].front(); 96 que1[e.to].pop_front(); 97 if( c[t]==s[r+1] ) 98 { 99 if( !mapp[t][r+1] ) mapp[t][r+1]=1; 100 } 101 } 102 } 103 if(c[t]==s[1]) que1[t].push_back(1); //起点或终点 104 if(c[t]==s[m]) que2[t].push_back(m); 105 } 106 107 108 109 110 bool test() //s的长度为1的情况 111 { 112 for(int i=1; i<=n; i++) 113 if(c[i]==s[1]) return true; 114 return false; 115 } 116 117 void init() 118 { 119 edge_cnt=0; 120 ans=false; 121 memset(head,-1,sizeof(head)); 122 for(int i=0; i<=n; i++) 123 mapp[i].reset(), 124 mapp2[i].reset(), 125 que1[i].clear(), 126 que2[i].clear(); 127 } 128 129 130 int main() 131 { 132 //freopen("input.txt", "r", stdin); 133 int t, a, b, Case=0; 134 cin>>t; 135 while(t--) 136 { 137 scanf("%d",&n); 138 init(); 139 for(int i=1; i<n; i++) 140 { 141 scanf("%d%d",&a,&b); 142 add_node(a,b); 143 add_node(b,a); 144 } 145 scanf("%s", c+1); 146 scanf("%s", s+1); 147 m=strlen(s+1); 148 149 DFS(1,-1); 150 if(m==1) 151 { 152 if( test() ) printf("Case #%d: Find\n", ++Case); 153 else printf("Case #%d: Impossible\n", ++Case); 154 } 155 else if(m<=n&&ans==true)printf("Case #%d: Find\n", ++Case); 156 else printf("Case #%d: Impossible\n", ++Case); 157 } 158 return 0; 159 }