AtCoder - ABC 270 - C(DFS+树上路径查询)

C - Simple path

题意:

给定一棵有 N 个节点的树和两个节点 x,y ,按顺序输出从节点 x 到节点 y 的路径。

数据范围:

1 ≤ N ≤ 2 × 10^{5}

1 ≤ X,Y ≤ N

思路1:

根据节点深度和父节点找路径。

先跑一遍DFS求出每个节点的深度后,对于求结点 a,b 的路径,我们需要维护两个数组vector,数组 v1,v2 分别存从节点 a,b 开始的路径;对于结点 a,b,优先深度深的节点往上爬,一直爬到两路径相遇于节点 t,注意这个节点是没有存在任意一个数组中的。
拼接数组中所存的节点,顺序输出数组 v1 ,再输出两路径相遇处的节点 t ,最后倒序输出数组 v2 即可。

Code:

#include<bits/stdc++.h>
#include<math.h>
using namespace std;

#define x first
#define y second
#define int long long
const int dx[] = { 1,-1,0,0 }, dy[] = { 0,0,1,-1 };

const int N = 200010, INF = 0x3f3f3f3f, mod = 998244353;

typedef pair<int, int>PII;

int n, x, y;
int ne[2*N], h[N], e[2*N], idx;
int dep[N], f[N];

//邻接表存图
void add(int a, int b)
{
	e[idx] = b;
	ne[idx] = h[a];
	h[a] = idx++;
}

//dfs求出所有节点的深度
void dfs(int u, int fa)
{
	dep[u] = dep[fa] + 1;
	f[u]=fa;

	for (int i = h[u]; i != -1; i = ne[i])     //遍历节点u的儿子节点
	{
		int j = e[i];
		if (j == fa)continue;
		dfs(j, u);
	}
}

void solve()
{
	cin >> n >> x >> y;

	memset(h, -1, sizeof(h));
	for (int i = 1; i <= n - 1; i++)
	{
		int a, b;
		cin >> a >> b;
		add(a, b), add(b, a);              //存边
	}

	dfs(1, 0);                             //深搜预处理出树中所有节点的深度

	vector<int>v1, v2;
	int a = x, b = y;
	while (a != b)                        //根据深度让深度深的节点往上爬,直到两节点的相遇
	{
		if (dep[a] > dep[b])v1.push_back(a), a = f[a];
		else v2.push_back(b), b = f[b];
	}

	reverse(v2.begin(), v2.end());         //将v2所存的点的顺序逆置

	for (auto it : v1)cout << it << " ";  //v1中存的是从节点x开始的一部分节点
	cout << a << " ";                     //v1,v2存边时,当遍历到a=b时跳出,则此时的节点a是v1所存点之后的点
	for (auto it : v2)cout << it << " ";  //输出后半部分所存的点
	cout << endl;
}

signed main()
{
	//int t;
	int t = 1;
	//cin >> t;
	while (t--)
	{
		solve();
	}

	return 0;
}

思路2:

可以证明,对于树中任意两个不同的顶点 a 和 b,存在一条唯一的从 a 到 b 的简单路径。

直接dfs,把节点 y 当做根节点,从该节点开始dfs预处理所有节点的父节点 fa[],要求的节点x到节点 y 的路径,就是从节点 x 一直向父节点遍历输出直到节点 y 即可。

Code:

#include<bits/stdc++.h>
#include<math.h>
using namespace std;

#define x first
#define y second
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);
const int dx[] = { 1,-1,0,0 }, dy[] = { 0,0,1,-1 };

const int N = 200010, INF = 0x3f3f3f3f, mod = 998244353;

typedef pair<int, int>PII;

int n, x, y;
vector<int>e[N];
int fa[N];

//dfs预处理所有节点的父节点
void dfs(int u)
{
	for(int &v:e[u])
		if (v != fa[u])
		{
			fa[v] = u;
			dfs(v);
		}
}

void solve()
{
	cin >> n >> x >> y;

	for (int i = 1; i <= n - 1; i++)
	{
		int u, v;
		cin >> u >> v;

		e[u].push_back(v);
		e[v].push_back(u);
	}

	dfs(y);                                //dfs从节点y开始,预处理所有节点的父节点

	for (int u = x; u; u = fa[u])          //dfs的预处理后,从节点x到节点y的路径就可以通过父节点联系在一起
		cout << u << " ";                  //从节点x开始向上走,直到节点y
	cout << endl;
}

signed main()
{
	IOS;

	//int t;
	int t = 1;
	//cin >> t;
	while (t--)
	{
		solve();
	}

	return 0;
}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
吐槽:害,有思路但是不会实现的痛苦,虽然不是难题,但是秉承着逢dfs必记录下原则的菜鸟还是写个题解鞭笞下。题目注意点:

1. 好久不写存图的题,有些细节处理忘记了。注意因为存无向图的是同一个边时存两次,所以下标为idx的数组ne[]和e[]初始化范围为2*N,不是N。

2. dfs预处理树中节点的深度,预处理以某一节点为根节点的所有节点的父节点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值