HDU 5469 Antonidas (树形DP,暴力)

题意:

  给一棵n节点的树图,每个点都是一个小写字母,要求找到两个点(a,b),从a->b的路径上形成了一个字符串为s。给出s,问是否存在这样的点对。

思路:

  考虑一个点,要么从该点出发,要么在该点结束,要么它作为一个中间点将左右两个串连起来成为s。叶子只能是起点或者终点。在每个点中需要保存两个队列,表示有点可以从正or反向走到这个点的长度(即前缀与后缀,但只需记录当前点是排在第几)。对于在本节点连接的情况,枚举一下哪些孩子可能在本节点连接就行了。

  2s多

  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 }

AC代码

时间: 2024-08-05 04:37:38

HDU 5469 Antonidas (树形DP,暴力)的相关文章

hdu 1011(树形dp)

Mark.看着吴神博客写的,还未完全懂. 1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string>

HDU 2196Computer(树形DP)

给你一颗边带权值的树,求树上的每一点距离其最远的一个点的距离 比较典型的题了,主要方法是进行两次DFS,第一次DFS求出每一个点距离它的子树的最远距离和次远距离,然后第二次DFS从父节点传过来另一侧的树上的距离它的最远距离进行一次比较便可得出任意点的最远距离了 之所以需要记录最远和次远是为了辨别父节点的最远距离是否是根据自己得来,如果是的话应该选择父节点的次远距离,保证结果的准确性 1 //#pragma comment(linker,"/STACK:102400000,102400000&qu

HDU 2196 Computer 树形DP经典题

链接:http://acm.hdu.edu.cn/showproblem.php? pid=2196 题意:每一个电脑都用线连接到了还有一台电脑,连接用的线有一定的长度,最后把全部电脑连成了一棵树,问每台电脑和其它电脑的最远距离是多少. 思路:这是一道树形DP的经典题目.须要两次DFS,第一次DFS找到树上全部的节点在不同子树中的最远距离和次远的距离(在递归中进行动态规划就可以),第二次DFS从根向下更新出终于答案.对于每次更新到的节点u,他的最远距离可能是来自u的子树,或者是u的父亲节点的最远

【BZOJ3696】化合物 树形DP+暴力

[BZOJ3696]化合物 Description 首长NOI惨跪,于是去念文化课了.现在,他面对一道化学题.    这题的来源是因为在一个奇怪的学校两个化竞党在玩一个奇怪的博弈论游戏.这个游戏很蛋疼,我相信你们也没有兴趣听.    由于这个游戏涉及博弈论,因此化竞的同学就要求首长求一个类似SG函数的值.    他们手中有一种非常神奇的化合物,它的分子由N个原子组成(不要在意一个原子可能和及其多个原子成键这个细节).这个分子构成一个树结构,1号分子为根.    若两个原子i.j到它们的最近公共祖

HDU 4714 Tree2cycle (树形DP)

题意:给定一棵树,断开一条边或者接上一条边都要花费 1,问你花费最少把这棵树就成一个环. 析:树形DP,想一想,要想把一棵树变成一个环,那么就要把一些枝枝叶叶都换掉,对于一个分叉是大于等于2的我们一定要把它从父结点上剪下来是最优的, 因为如果这样剪下来再粘上花费是2(先不管另一端),如果分别剪下来再拼起来,肯定是多花了,因为多了拼起来这一步,知道这,就好做了.先到叶子结点, 然后再回来计算到底要花多少. 代码如下: #pragma comment(linker, "/STACK:10240000

HDU 3899 简单树形DP

题意:一棵树,给出每个点的权值和每条边的长度, 点j到点i的代价为点j的权值乘以连接i和j的边的长度.求点x使得所有点到点x的代价最小,输出 虽然还是不太懂树形DP是什么意思,先把代码贴出来把. 这道题目的做法是:先进行一次DFS,以每个节点为根,求出它下面节点到它的数量和. 再进行一次DFS,以每个节点为根,求出它下面节点到它的花费总和. source code: #pragma comment(linker, "/STACK:16777216") //for c++ Compile

HDU 4313 Matrix 树形dp

题意: 给定n个点的树,m个黑点 以下n-1行给出边和删除这条边的费用 以下m个黑点的点标[0,n-1] 删除一些边使得随意2个黑点都不连通. 问删除的最小花费. 思路: 树形dp 每一个点有2个状态,成为黑点或白点. 若本身这个点就是黑点那么仅仅有黑点一种状态. 否则能够觉得是子树中某个黑点转移上来. 所以dp[i][0]是i点为黑点的状态. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <st

HDU 2196 Computer 树形DP 经典题

给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权,放在数组cost中 令tree(i)表示以节点i为根的子树 对于节点i,离该节点最远的点要不就是在tree(i)中,要不就是在father(i)上面 令: dp[i][1] : 在子树tree(i)中,离i最远的距离 dp[i][2] : 在子树tree(i)中,离i第二远的距离 (递推的时候需要)

HDU 5469 Antonidas

Antonidas Time Limit: 4000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 546964-bit integer IO format: %I64d      Java class name: Main Given a tree with N vertices and N−1 edges. Each vertex has a single letter Ci. Given a