- 玄关求调
玄关求调0008
- @ 2025-9-4 21:28:02
给出一个有 n 个顶点和 m 条边的无向连通图 G,没有重边和自环。
顶点的编号为 1∼n,边的编号为 1∼m,第 i 条边连接顶点 ui 和 vi。
给出图上三个不同的顶点 A,B,C。判断是否有从点 A 经过点 B 到点 C 的简单路径。
简单路径指路径上的点互不相同,即不重复经过同一个点。
注意本题有多组测试数据(最多不超过10组),最后以0 0结束。
输入格式:
第一行有两个整数 n,m。 第二行有三个整数 A,B,C。 接下来 mm 行,每行两个整数 u_i 和 v_i。
输出格式:
对于每一组测试数据输出一行 Yes 或 No。
限制:
- 3≤n≤2×1e5
- n−1≤m≤min(n(n−1)/2,2×1e5)
- 1≤A,B,C≤n
- 1≤ui<vi≤n
修改代码,不用vector开数组,但用它建图
// 简单路径
#include <cstdio>
#include <vector>
#include <stack>
using namespace std;
const int N = 2e5 + 2047;
int n, m, sa, sb, sc, tot, cnt;
int dfn[N], low[N], f[N];
vector<int> a[N], na[N];
stack<int> st;
int s[N], top, tp;
int min(int x, int y) { return x < y ? x : y; }
void tarjan(int u) {
dfn[u] = low[u] = ++tot;
//st.push(u);
s[++top] = u;
for (int v : a[u]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
if (low[v] == dfn[u]) {
na[++cnt].push_back(u);
na[u].push_back(cnt);
// do {
// if (!st.empty()) {
// top = st.top();
// st.pop();
// na[top].push_back(cnt);
// na[cnt].push_back(top);
// }
//} while (top != v);
while(s[top] != v) {
tp = s[top--];
na[cnt].push_back(tp); // 方点连接点双内节点
na[tp].push_back(cnt);
}
na[cnt].push_back(v);
na[v].push_back(cnt);
top--;
// if (!st.empty()) st.pop();
}
} else low[u] = min(low[u], dfn[v]);
}
}
void dfs(int u, int fa) {
f[u] = fa;
for (int v : na[u]) {
if (v == fa) continue;
dfs(v, u);
}
}
bool check(int u) {
while (u != sc) {
if (u > n) {
for (int v : na[u]) {
if (v == sb) return 1;
}
}
u = f[u];
}
return 0;
}
int main()
{
while (scanf("%d %d", &n, &m)) {
if (!n && !m) break;
for (int i = 1; i <= cnt; i++) {
a[i].clear();
na[i].clear();
f[i] = low[i] = dfn[i] = 0;
if (!st.empty()) st.pop();
}
tot = 0;
cnt = n;
scanf("%d %d %d", &sa, &sb, &sc);
for (int u, v; m--;) {
scanf("%d %d", &u, &v);
a[u].push_back(v);
a[v].push_back(u);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i);
}
dfs(1, 0);
bool flag = check(sa);
if (flag) puts("Yes");
else puts("No");
}
return 0;
}
1 条评论
-
-
// 简单路径 #include <cstdio> #include <vector> #include <stack> using namespace std; const int N = 2e5 + 2047; int n, m, sa, sb, sc, tot, cnt; int dfn[N], low[N], f[N]; vector<int> a[N], na[N]; int s[N], top, tp; int min(int x, int y) { return x < y ? x : y; } void tarjan(int u) { dfn[u] = low[u] = ++tot; s[++top] = u; for (int v : a[u]) { if (!dfn[v]) { tarjan(v); low[u] = min(low[u], low[v]); // ★ 改1:条件 >=,否则会漏点双 if (low[v] >= dfn[u]) { na[++cnt].push_back(u); na[u].push_back(cnt); // ★ 改2:先弹到 v,再单独处理 v while (s[top] != v) { tp = s[top--]; na[cnt].push_back(tp); na[tp].push_back(cnt); } tp = s[top--]; na[cnt].push_back(tp); na[tp].push_back(cnt); } } else { low[u] = min(low[u], dfn[v]); } } } void dfs(int u, int fa) { f[u] = fa; for (int v : na[u]) { if (v == fa) continue; dfs(v, u); } } bool check(int u) { while (u != sc && u != 0) { if (u > n) { for (int v : na[u]) { if (v == sb) return 1; } } u = f[u]; } if (u == sb) return 1; // ★ 改3:sc 本身是 B 的情况 return 0; } int main() { while (scanf("%d %d", &n, &m)) { if (!n && !m) break; // ★ 改4:清理范围到 cnt,重置变量 for (int i = 1; i <= cnt; i++) { a[i].clear(); na[i].clear(); f[i] = low[i] = dfn[i] = 0; } tot = top = 0; cnt = n; scanf("%d %d %d", &sa, &sb, &sc); for (int u, v; m--;) { scanf("%d %d", &u, &v); a[u].push_back(v); a[v].push_back(u); } for (int i = 1; i <= n; i++) { if (!dfn[i]) tarjan(i); } // ★ 改5:DFS 从 sa 开始,保证父链能到 sc dfs(sa, 0); bool flag = check(sa); if (flag) puts("Yes"); else puts("No"); } return 0; }
- 1