1 条题解
-
0
我们先给一个图。

由图可知有 $(1,8),(1,9),(1,10),(2,8),(2,9),(2,10),(3,8),(3,9),(3,10)$ 这几对点满足题意要求。
通过观察可以发现 与 之间的节点所通向的路径,无论是通向 的左边,还是通向 的右边,都不会包含 或 。
假设以节点序号较小为起点,较大为终点,我们可以得到:以 左边的节点为起点,以 右边的节点为终点,所构成的路径一定包含 与 。

显然,一个节点把图分为两边,那么图的左边除了经过该节点,没有可以不经过该节点而到达图的右边的路径。也就是,这个节点无可避免地经过 和 ,无法绕路。而最后 的数量,就是 左边的节点数量 右边的节点数量。
考虑搜索。我们先假定起点为 ,终点为 。从 出发开始搜,到 为止,没有搜到的点就是 右边的点。(参见下图)

黄线为以 为起点会搜到的路径,只要给搜到的点打上标记,就可以知道 右边点的数量。同理,我们以 为起点,也可以搜出 左边的点。两边的答案相乘,就可以得到题目的答案。
那么如何实现呢?
-
设一个记录访问的数组 。
-
给终点( 或 )先打上标记,搜到那里时就停。
-
只要碰到没有搜过的,就继续搜下去。因为终点已经打上标记的,而且是联通图,所以没搜到的点就一定是 左边或 右边。
这样,我们很容易使用
bfs或dfs解决此题。#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; const int M = 1e6 + 10; int n, m, a, b; vector<int>e[N]; bool vis[N]; long long s1, s2; void dfs(int x) { for (int k = 0; k < e[x].size(); k++) { int y = e[x][k]; if (!vis[y]) vis[y] = 1, dfs(y); // 只要没有访问到的,打上标记,继续 dfs } } void run(void) { scanf("%d%d%d%d", &n, &m, &a, &b); for (int i = 1, u, v; i <= m; ++i) { scanf("%d%d", &u, &v); e[u].push_back(v); e[v].push_back(u); } vis[b] = 1; dfs(a); for (int i = 1; i <= n; ++i) if (!vis[i]) ++s1; // 统计 memset(vis, 0, sizeof(vis)); vis[a] = 1; // 不要忘记给终点打标记 dfs(b); for (int i = 1; i <= n; ++i) if (!vis[i]) ++s2; printf("%lld\n", s1 * s2); } int main() { freopen("junction.in", "r", stdin); freopen("junction.out", "w", stdout); run(); return 0; } -
- 1
信息
- ID
- 177
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者