先抽象出一棵以1做为根结点的树。给定了访问序列a[1..m]。

考虑两种特殊情况:

1.访问了某个a[j],但是存在a[i]没有访问且i < j,出现这种情况说明a[j]一定是a[i]的祖先节点,必须访问过a[j]才能访问a[i],这种情况是不符合条件的。

2.当某个点被访问后并且这个节点被回溯之后,它的子树中仍然存在序列中的节点没被访问,那么些节点不会有机会再被访问,不符合情况。

思路:根据访问序列中节点的下标,给定所有待访问节点一个权值,代表他们的访问顺序,例如数据:

7
1 2
1 3
2 4
2 5
3 6
3 7
3
3 2 7

这组数据中,分别给3 2 7 一个权值,w[3] = 0, w[2] = 1, w[7] = 2, 其他节点的权值都是inf,dp[i]表示以节点i作为根结点的子树中最小的权值,如果某个节点i下面存在权值比它小的节点j,说明满足第一种情况,肯定是不合理的。

当处理了第一种情况,并且得到了所有dp[i],那么现在要开始处理第二种情况。模拟深度优先遍历这棵树即可,在遍历的同时,一定是按照给定的访问序列来顺序访问,给一个全局变量f,代表当前需要访问的节点的权值,假设当前在i节点处,它的子节点是Vj,那么一定是优先访问dp[Vj] = f的节点,然后继续找,知道有节点u满足w[u] = f,说明找到了这个节点,让f++,该寻找下一个节点了,一直重复即可,注意每个节点只访问一次,当出现要访问某个被访问过的节点时,就说明符合第二种情况。其实这种方法也可以处理第一种情况,由于要预处理dp[i],所以我在建树的同时就把第一种情况处理了。最后判断序列中是否有没被访问过得节点,有则说明是满足第二种情况的。总的复杂度是O(n*logn)

贴一组我认为很容易WA的测试数据:

6

4

1 2

2 3

3 4

3

4 3 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

4

1 2

2 3

3 4

4

4 3 2 1

7

1 2

1 3

2 4

2 5

3 6

3 7

4

2 4 3 5

9

1 2

1 3

2 4

2 5

3 6

3 7

4 8

4 9

5

2 4 8 5 9

正确答案是:

NO

YES

NO

NO

NO

NO

AC代码:

#include <cstdio>
#include <cmath>
#include <cctype>
#include <bitset>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int>
typedef long long LL;
const int maxn = 100 + 5;
vector<int>G[maxn];
int vis[maxn], w[maxn], a[maxn], dp[maxn];
int n, m;

bool build_tree(int u, int par) {
	if(G[u].size() == 1 && G[u][0] == par) {
		dp[u] = w[u];
		return true;
	}
	int ans = inf;
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		if(v == par) continue;
		if(!build_tree(v, u)) return false;
		if(w[u] != inf && w[u] > dp[v]) return false;
		ans = min(ans, dp[v]);
	}
	dp[u] = min(ans, w[u]);
	return true;
}

int f;
void dfs(int u,int par) {
	vis[u]++;
	if(w[u] == f) f++;
	if(f >= m) return;
	for(int i = 0; i < G[u].size(); ++i) {
		int v = G[u][i];
		if(v == par) continue;
		if(!vis[v] && dp[v] == f) { //未访问过f能在以v为根结点的子树中找到
			dfs(v, u);
		}
	}
}

bool cmp(int a, int b) {
	return dp[a] < dp[b];
}

bool solve(int n, int m) {
	//以第一个点为根建树
	bool ok = build_tree(1, -1);
	if(!ok) return false;
	for(int i = 1; i <= n; ++i) {
		//排序,根据节点的权值确定访问顺序
		sort(G[i].begin(), G[i].end(), cmp);
	}
	f = 0;
	dfs(1, -1);
	for(int i = 0; i < m; ++i) {
		if(!vis[a[i]]) return false;
 	}
 	return true;
}
int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		for(int i = 1; i <= n+1; ++i) G[i].clear();
		int u, v;
		for(int i = 0; i < n-1; ++i) {
			scanf("%d%d", &u, &v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		memset(vis, 0, sizeof(vis));
		for(int i = 1; i <= n; ++i) w[i] = inf;
		scanf("%d", &m);
		//赋予权值
		for(int i = 0; i < m; ++i) {
			scanf("%d", &a[i]);
			w[a[i]] = i;
		}
		int ok = solve(n, m);
		if(ok) printf("YES\n");
		else printf("NO\n");
	}
	return 0;
}

如有不当之处欢迎指出!

hiboCoder 1041 国庆出游 dfs+思维的更多相关文章

  1. hihoCoder 1041 国庆出游 (DFS)

    题意: 小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比较有特色:它共有n座城市(编号1-n):城市之间恰好有n-1条公路相连,形成一个树形公路网.小Hi计划从A国首都(1号城市)出发,自驾遍历 ...

  2. hihoCoder 1041 国庆出游 最详细的解题报告

    题目来源:国庆出游 解题思路(下面是大神的写的): 把题目中的序列称作S,树称作T.那么对于S中的任意节点x,x的子孙节点如果在S出现的话,那么这个子孙节点的位置是有一定要求的:x的所有子孙节点在S中 ...

  3. 【hihoCoder】1041. 国庆出游

    问题:详见http://hihocoder.com/problemset/problem/1041 有n个城市,城市编号为1-n,城市间有n-1条路(所以,城市路网是一棵树).给定一个序列S,要求判断 ...

  4. hihocoder——1041国庆出游(搜索)

    描述 小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比较有特色:它共有n座城市(编号1-n):城市之间恰好有n-1条公路相连,形成一个树形公路网.小Hi计划从A国首都(1号城市)出发,自驾遍历所 ...

  5. 【hiho1041】国庆出游 dfs+bitset

    题目大意:给定一棵 N 个节点的有根树,1 号节点为根节点,现遍历整棵树,要求每条边仅被经过两次,问是否存在一种特定的遍历方式使得 dfs 序中节点的相对前后关系符合给定的顺序. 题解: 首先,由于要 ...

  6. hdu6035[dfs+思维] 2017多校1

    /*hdu6035[dfs+思维] 2017多校1*/ //合并色块, 妙啊妙啊 #include<bits/stdc++.h> using namespace std; ; const ...

  7. Hiho1041 国庆出游 搜索题解

    题目3 : 国庆出游 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描写叙述 小Hi和小Ho准备国庆期间去A国旅游.A国的城际交通比較有特色:它共同拥有n座城市(编号1-n): ...

  8. D. Eternal Victory(dfs + 思维)

    D. Eternal Victory time limit per test 2 seconds memory limit per test 256 megabytes input standard ...

  9. 国庆出游神器:魔幻黑科技换天造物,让vlog秒变科幻大片!

    摘要:国庆旅游景点人太多,拍出来的照片全是人人人.车车车,该怎么办?不妨试试这个黑科技,让你的出游vlog秒变科幻大片. 本文分享自华为云社区<国庆出游神器,魔幻黑科技换天造物,让vlog秒变科 ...

随机推荐

  1. 如何去掉ul标签的多余空白或多余大距离?

    在css中写入 ul{ margin:; padding:; list-style: none; } 让其内边距和外边距为0,列表样式为空

  2. python 中 reversed()函数

    一个列表a: a=[1,2,3,4,5,6,7] 一个对象b: b=reversed(a) 输出: print(b) <list_reverseiterator object at 0x0000 ...

  3. junit断言总结

    我们平时编写自己的测试类,如果没有断言,那么就没写测试的必要了. JUnit框架用一组assert方法封装了最常见的测试任务.这些assert方法可以极大地简化单元测试的编写. Assert类包含了一 ...

  4. linkin大话java

    青春不灭,理想犹存,linkin--勿忘初心! 不知不觉已经和java并肩作战将近了2年,在这2年之中模模糊糊研究了java2ee领域的好多东西,但是都没有做系统的整理.以前写的笔记也是零零散散不成一 ...

  5. 日历插件——laydate.js

    laydate是一款很好用的日历控件,兼容了包括IE6在内的所有主流浏览器,默认有三种皮肤,如需其它皮肤可去官网下载http://www.layui.com/laydate/  一.核心方法:layd ...

  6. sed,n,N,d,D,p,P,h,H,g,G,x,解析

    原文地址 这篇文章主要是我参考命令的,直接复制粘贴,有问题请拍砖 A. sed执行模板=sed '模式{命令1;命令2}' 即逐行读入模式空间,执行命令,最后输出打印出来 B. p打印当前模式空间所有 ...

  7. Activity组件安全(下)

    什么是Activity劫持 简单的说就是APP正常的Activity界面被恶意攻击者替换上仿冒的恶意Activity界面进行攻击和非法用途.界面劫持攻击通常难被识别出来,其造成的后果不仅会给用户带来严 ...

  8. CSS继承、层叠和特殊性

    1.继承 (1)样式应用于某个特定的HTML标签元素,而且应用于其后代. (2)但某些标签不适用,如border: (3)例子:p{color:red;}设置了颜色 <p class=" ...

  9. 有关mysql的for update以及 死锁问题

    一.先说锁的概念 锁级别: 1.行级锁: InnoDB引擎(也支持表级锁,默认是行级锁),开销大,加锁慢:会出现死锁.锁定粒度最小,发生锁冲突的概率最低,并发度最高. 2.表级锁:MylSAM引擎和M ...

  10. python之闭包与装饰器

    python闭包与装饰器 闭包 在函数内部定义的函数包含对外部的作用域,而不是全局作用域名字的引用,这样的函数叫做闭包函数. 示例: #-------------------------------- ...