题目链接:
根据题意我们只需要找出一个点使得它能将两个信息中心变得不连通即可:
即找出一个割点,它能将两个信息中心 a, b 所在的一个连通图,分割为a, b不能到达的两个图:
如何判断上述条件呢??
首先:dfn[u] <= dfn[a] 表示点a在点u的子树中,若dfn[u] > dfn[b] 表示b不在u的子树中,此时满足将u这个割点去掉a, b不连通。
但这个判断条件有一个bug就是a, b都在点u的子树中则无法判断
如图:
此时用上述条件无法判断答案,因为此时去点割点u仍能满足条件,但不包括上述条件的限制。
但是我们可以找 u 遍历到的下一个节点 v ,假设点A先被遍历点v在点A后被遍历, 所以此时仍然满足dfn[v] <= dfn[b] && dfn[v] < dfn[a],满足条件所以当u是割点时用点v来判断是包括用点u判断的情况的
若点B先被遍历,同理可以满足条件:
代码如下:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 200010, M = 500010 * 2; int n; int a, b; bool st[N]; int h[N], e[M], ne[M], idx; int dfn[N], low[N], timestamp; void add(int a, int b) { e[idx] = b; ne[idx] = h[a]; h[a] = idx; idx ++ ; } bool check(int v) { if (dfn[v] <= dfn[a] && dfn[v] > dfn[b]) return true;//若a是v的子树,但b不是v的子树 if (dfn[v] <= dfn[b] && dfn[v] > dfn[a]) return true; return false; } void tarjan(int u, int fa) { low[u] = dfn[u] = ++ timestamp; for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; if (!dfn[j]) { tarjan(j, u); low[u] = min(low[u], low[j]); if (low[j] >= dfn[u] && u != a && u != b && check(j))//若u是割点且割点不是a, b; st[u] = true; } else if (j != fa) low[u] = min(low[u], dfn[j]); } } int main() { cin >> n; memset(h, -1, sizeof h); int x, y; while (scanf("%d %d", &x, &y), x || y) add(x, y), add(y, x); cin >> a >> b; tarjan(a, -1);//从其中一个信息中心开始遍历 for (int i = 1; i <= n; i ++ ) if (st[i]) { printf("%d", i); return 0; } puts("No solution"); return 0; }