2021-2022-2 ACM集训队每周程序设计竞赛(9) - 问题 F: 乔斯达家族世世代代都是绅士 - 题解

题意:

一个拥有 n n n 个点, n − 1 n-1 n1 条边的无向联通图。现在有两个特殊点 u , v u,v u,v u u u 想尽可能的远离 v v v,而 v v v 想尽可能的接近 u u u

现有如下流程:

  1. 如果 u , v u,v u,v在一个节点上,那么结束。否则 u u u 可以移动到与当前节点相邻的任意一个其他节点。
  2. 如果 u , v u,v u,v在一个节点上,那么结束。否则 v v v 可以移动到与当前节点相邻的任意一个其他节点。
  3. 回到步骤1。

两个点均按最优解进行,请计算出结束前 v v v 所进行的操作数。

思路:

这道题的结论……我不好说,咱们还是直接看解法吧,差不多看完解法就懂做法了。

首先我们需要先把 u , v u,v u,v 两点到图上任意一点的最短距离求出来,设为 d u [ ] , d v [ ] du[],dv[] du[],dv[]
那么如果 d u [ i ] < d v [ i ] du[i]<dv[i] du[i]<dv[i],那么 u u u 在到达该点时,以及在到达该点之前比不可能被抓到,这一点可以通过反证法轻松证得;
如果 d u [ i ] = = d v [ i ] du[i]==dv[i] du[i]==dv[i],那么可能是在该点时被抓到的,也可能不是。也就是说如果到达该点,必定结束,但是我们所求的是结束前的最大操作数,所以无用;
如果 d u [ i ] > d v [ i ] du[i]>dv[i] du[i]>dv[i],不用多说,也必不可能是该点。

所以,综上所述,我们只需找到 d u [ i ] < d v [ i ] du[i]<dv[i] du[i]<dv[i] 时, d v [ ] dv[] dv[] 的最大值即可。

时间复杂度: O ( n ) O(n) On

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
int n;
int e[N], ne[N], h[N], idx;
int l[N], r[N];
int st, ed;

void add(int a, int b) {
	e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void bfs(int fa, int u, int *d) {
	for (int i = h[u]; i != -1; i = ne[i]) {
		int j = e[i];
		if (j == fa)
			continue;
		d[j] = d[u] + 1;
		bfs(u, j, d);
	}
}

signed main() {

	cin >> n >> st >> ed;
	for (int i = 1; i <= n; i++)
		h[i] = -1;
	for (int i = 1, x, y; i < n; i++) {
		scanf("%lld %lld", &x, &y);
		add(x, y), add(y, x);
	}

	bfs(0, st, l), bfs(0, ed, r);

	int res = 0;
	for (int i = 1; i <= n; i++)
		if (l[i] < r[i])
			res = max(res, r[i]);

	cout << res - 1;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值