题目链接:传送门
-
2 7 1 2 1 3 2 4 2 5 3 6 3 7 3 3 7 2 7 1 2 1 3 2 4 2 5 3 6 3 7 3 3 2 7
样例输出
-
YES NO
描述
小Hi和小Ho准备国庆期间去A国旅游。A国的城际交通比较有特色:它共有n座城市(编号1-n);城市之间恰好有n-1条公路相连,形成一个树形公路网。小Hi计划从A国首都(1号城市)出发,自驾遍历所有城市,并且经过每一条公路恰好两次——来回各一次——这样公路两旁的景色都不会错过。
令小Hi苦恼的是他的小伙伴小Ho希望能以某种特定的顺序游历其中m个城市。例如按3-2-5的顺序游历这3座城市。(具体来讲是要求:第一次到达3号城市比第一次到达2号城市早,并且第一次到达2号城市比第一次到达5号城市早)。
小Hi想知道是否有一种自驾顺序满足小Ho的要求。
输入
输入第一行是一个整数T(1<=T<=20),代表测试数据的数量。
每组数据第一行是一个整数n(1 <= n <= 100),代表城市数目。
之后n-1行每行两个整数a和b (1 <= a, b <= n),表示ab之间有公路相连。
之后一行包含一个整数m (1 <= m <= n)
最后一行包含m个整数,表示小Ho希望的游历顺序。
输出
YES或者NO,表示是否有一种自驾顺序满足小Ho的要求。
解题思路:对于a1,a2....an,假如这n个点位于以1为根的b1,b2...bn个不同分支上,显然是成立的,若在分支bi上增加一个点p,若仍要成立,则在遍历分支bi时,要同时遍历完ai和p,则p点一定要紧挨在ai后,即.....ai,p......。所以对于序列中的所有ai结点的子节点都要紧跟在ai后面。写个搜索进行处理(比较巧妙)
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#include <set>
#include <string>
#include <stack>
#include <algorithm>
#include <map>
#include <bitset>
using namespace std;
typedef long long ll;
const int N = 110;
const int M = 100000000;
const int INF = 0x3fffffff;
const int mod = 1e9+7;
const double Pi = acos(-1.0);
const double sm = 1e-9;
bitset<N>rec[N];
int vis[N],data[N],flag,num;
struct Edge{
int node;
Edge*next;
}m_edge[N*2];
Edge*head[N];
int Ecnt;
void init()
{
Ecnt = 0;
fill( head , head+N , (Edge*)0 );
fill( vis , vis+N , 0 );
for( int i = 0 ; i < N ; ++i )
rec[i].reset();
}
void mkEdge( int a , int b )
{
m_edge[Ecnt].node = b;
m_edge[Ecnt].next = head[a];
head[a] = m_edge+Ecnt++;
}
//获取结点i的所有子节点
void dfs( int u )
{
vis[u] = 1;
rec[u][u] = 1;
for( Edge*p = head[u] ; p ; p = p->next ){
int v = p->node;
if( !vis[v] ){
dfs( v );
rec[u] |= rec[v];
}
}
}
void solve( int u , int m )
{
vis[u] = 1;
if( u == data[num] ){
++num;
}
//m个点都按顺序遍历到了,则满足条件
if( num == m ){
flag = true;
return;
}
//num<m这个判断条件保证了树中所有结点都会遍历到
while( num < m ){
int temp = num;
for( Edge*p = head[u] ; p ; p = p->next ){
int v = p->node;
//寻找data[i]结点的最近根结点,若存在,则继续向下寻找data[i+1]
if( !vis[v] && rec[v][data[num]] ){
solve( v , m );
}
}
//向下若没有找到,则返回,不会再去找对于data[i]的根结点(因为向下跑时都访问过了)
//即若data[i+1]是data[i]的根结点,则找不到解,会返回
if( num == temp ) break;
}
}
int main()
{
int T,n,m,a,b;
scanf("%d",&T);
while( T-- ){
init();
scanf("%d",&n);
for( int i = 0 ; i < n-1 ; ++i ){
scanf("%d%d",&a,&b);
mkEdge(a,b);
mkEdge(b,a);
}
scanf("%d",&m);
for( int i = 0 ; i < m ; ++i ){
scanf("%d",&data[i]);
}
dfs(1);
flag = num = 0;
fill( vis , vis+N , 0 );
solve( 1 , m );
if( flag ) printf("YES\n");
else printf("NO\n");
}
return 0;
}