HihoCoder1041 国庆出游 树形DP第四题

小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的要求。

Input

输入第一行是一个整数T(1<=T<=20),代表测试数据的数量。

每组数据第一行是一个整数n(1 <= n <= 100),代表城市数目。

之后n-1行每行两个整数a和b (1 <= a, b <= n),表示ab之间有公路相连。

之后一行包含一个整数m (1 <= m <= n)

最后一行包含m个整数,表示小Ho希望的游历顺序。

Output

YES或者NO,表示是否有一种自驾顺序满足小Ho的要求。

Sample Input

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

Sample Output

YES
NO

实际也算不上是DP,感觉就是搜索。自己的思路,1A,开心。

思路:你如果访问了一个节点node,你必须也把子树中需要访问的给访问了,不然你的fa_node到node这条路将走超过两遍。

要求:node的几个子树中需要访问的点肯定要在顺序的相连位置。

其中:sa是每个点的顺序,son[node]表示node根下需要访问的点的顺序

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<memory>
#include<cstring>
using namespace std;
int sa[110],son[110][110];//sa是每个点的顺序,son[node]表示node根下需要访问的点的顺序
int Laxt[220],Next[220],To[220],cnt,vis[110];

void _add(int u,int v)//加边
{
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}

bool _check(int u)//检查不包括u节点的u的子树中需要访问的点的顺序是否连续
{
    sort(son[u]+1,son[u]+1+son[u][0]);//排序后方便检查
    for(int i=2;i<=son[u][0];i++)
       if(son[u][i]!=son[u][i-1]+1) return false;
    return true;
}

bool _dfs(int u)
{
    vis[u]=1;
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i];
        if(vis[v])  continue;
        if(!_dfs(v)) return false;
        for(int j=1;j<=son[v][0];j++)  son[u][++son[u][0]]=son[v][j];//加子树
    }
    if(!_check(u))return false;//检查子树
    if(sa[u]&&son[u][0]>0&&sa[u]+1!=son[u][1]) return false;//根是不是第一个
    if(sa[u]) son[u][++son[u][0]]=sa[u];//加根
    return true;
}

int main()
{
    int T,i,j,n,m,u,v;
    scanf("%d",&T);

    while(T--){
        memset(sa,0,sizeof(sa));
        memset(Laxt,0,sizeof(Laxt));
        memset(son,0,sizeof(son));
        memset(vis,0,sizeof(vis));
        cnt=0;

        scanf("%d",&n);
        for(i=1;i<n;i++) {
            scanf("%d%d",&u,&v);
            _add(u,v);_add(v,u);
        }

        scanf("%d",&m);
        for(i=1;i<=m;i++){
            scanf("%d",&j);sa[j]=i;
        }

        if(_dfs(1)) printf("YES\n");
        else printf("NO\n");

    }
    return 0;
}
时间: 2024-10-11 08:57:16

HihoCoder1041 国庆出游 树形DP第四题的相关文章

HihoCoder1050 树中的最长路 树形DP第三题(找不到对象)

题意:求出的树中距离最远的两个结点之间相隔的距离. 水题一道,以前只会用路的直径来解. 代码如下: #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<memory> #include<algorithm> using namespace std; const int maxn=200010; int dis[maxn],La

树形DP的一些题

问题1 (http://zhengruioi.com/problem/1030) \(n\) 个点的树,点有点权,定义一个连通块的贡献为其中所有点的点权和的平方.现在要求所有连通块的贡献之和.\(n\leq 5\times 10^5\) sol: 考虑把平方式展开,\((a+b)^2=a^2+b^2+2ab\) 那么实质上就是要维护三个数组\(f[x], g[x], h[x]\),分别表示\(x\) 子树所有连通块权值和的平方,权值的和,还有连通块的个数.转移就很简单了. #include <b

POJ 1849 Two(树的直径--树形DP)(好题)

大致题意:在某个点派出两个点去遍历所有的边,花费为边的权值,求最少的花费 思路:这题关键好在这个模型和最长路模型之间的转换,可以转换得到,所有边遍历了两遍的总花费减去最长路的花费就是本题的答案,要思考,而且答案和派出时的起点无关 求最长路两遍dfs或bfs即可,从任意点bfs一遍找到最长路的一个终点,再从这个终点bfs找到起点 //1032K 79MS C++ 1455B #include<cstdio> #include<iostream> #include<cstring

CF482D Random Function and Tree 树形DP + 思维 + 神题

Code: #include<bits/stdc++.h> #define ull unsigned long long #define MOD 1000000007 #define ll long long #define maxn 120000 using namespace std; void setIO(string s) { string in=s+".in"; string out=s+".out"; freopen(in.c_str(),&

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第二远的距离 (递推的时候需要)

洛谷P1352 没有上司的舞会(树形DP水题)

题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了.所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数. 输入输出格式 输入格式: 第一行一个整数N.(1<=N<=6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri.(-128<=Ri

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

【BZOJ-2435】道路修建 (树形DP?)DFS

2435: [Noi2011]道路修建 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3115  Solved: 1002[Submit][Status][Discuss] Description 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿意修建恰好 n – 1条双向道路. 每条道路的修建都要付出一定的费用, 这个费用等于道路长度乘以道路两端的国家

选课(洛谷_2014)——树形dp

我是来复习一下树形dp的 这题,需要了解--左儿子右兄弟--也就是说,这是一个多叉树转二叉树的方法,儿子位置不变,兄弟的位置变成右儿子 然后就和二叉苹果树差不多了. #include<iostream> #include<cstdio> #define max(a,b) a>b?a:b using namespace std; inline int read(){ int t=1,num=0;char c=getchar(); while(c>'9'||c<'0'