版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89787306
【题目链接】
【思路要点】
- 不难发现各个边双连通分量可以分开处理,桥边可以直接删除。
- 可以证明,对于每一个边双连通分量,当 超过 级别,答案一定为 。
- 那么,将剩余图中的度为 的点缩去,剩余的图是一张点数和边数均在 级别的图。
- 选择一个起始点,找到包含其的所有环,再删去该起始点,每个环会被搜到恰好 次。
- 每走出一步均判断当前点与起始点的连通性以确保能够搜到一个环。
- 至多会搜到 个环,每个环环长为 个点,判断连通性需要 的时间。
- 总时间复杂度 。
- 互测当时笔者采用没有判断连通性的做法配合贪心和卡时输出 通过了本题。
【代码】
// Standard Solution O(N ^ 2) #include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int MAXM = 1e6 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int x[MAXM], y[MAXM], f[MAXN]; int n, m, em, v, e, ans[MAXN]; vector <int> a[MAXN], p; set <int> b[MAXN]; vector <pair <pair <int, int>, int>> c[MAXN]; bool vis[MAXN], vise[MAXN], iskey[MAXN]; bool instack[MAXN]; int tot, belong[MAXN], top, Stack[MAXN]; int timer, dfn[MAXN], low[MAXN]; void tarjan(int pos, int fa) { low[pos] = dfn[pos] = ++timer; v++, e += a[pos].size(); Stack[++top] = pos; instack[pos] = true; for (unsigned i = 0; i < a[pos].size(); i++) { if (a[pos][i] == fa) continue; if (dfn[a[pos][i]] == 0) { tarjan(a[pos][i], pos); low[pos] = min(low[pos], low[a[pos][i]]); } else if (instack[a[pos][i]]) low[pos] = min(low[pos], dfn[a[pos][i]]); } if (low[pos] == dfn[pos]) { int tmp = Stack[top--]; belong[tmp] = ++tot; instack[tmp] = false; while (tmp != pos) { tmp = Stack[top--]; belong[tmp] = tot; instack[tmp] = false; } } } void rebuild(int from, int fa, int pos, int len) { b[fa].erase(pos), b[pos].erase(fa); if (iskey[pos]) { if (from == pos) { ans[len] += 2; if (ans[len] >= 3) { puts("Yes"); exit(0); } return; } c[from].emplace_back(make_pair(pos, len), ++em); c[pos].emplace_back(make_pair(from, len), em); return; } int dest = *b[pos].begin(); rebuild(from, pos, dest, len + 1); } void dfs(int pos) { vis[pos] = true; v++, e += b[pos].size(); for (auto x : b[pos]) if (!vis[x]) dfs(x); } int F(int x) { if (f[x] == x) return x; else return f[x] = F(f[x]); } bool connected(int a, int b) { for (auto x : p) f[x] = x; for (auto x : p) for (auto y : c[x]) if (!vise[y.second]) f[F(x)] = F(y.first.first); return F(a) == F(b); } void work(int pos, int from, int depth) { if (!connected(pos, from)) return; if (depth && pos == from) { if (++ans[depth] >= 3) { puts("Yes"); exit(0); } return; } while (!c[pos].empty() && c[pos].back().first.first < from) c[pos].pop_back(); for (unsigned i = 0; i < c[pos].size(); i++) { pair <pair <int, int>, int> x = c[pos][i]; if (!vise[x.second] && !vis[x.first.first]) { vise[x.second] = vis[x.first.first] = true; work(x.first.first, from, depth + x.first.second); vise[x.second] = vis[x.first.first] = false; } } } int main() { read(n), read(m); for (int i = 1; i <= m; i++) { read(x[i]), read(y[i]); a[x[i]].push_back(y[i]); a[y[i]].push_back(x[i]); } for (int i = 1; i <= n; i++) { if (dfn[i] == 0) { v = 0, e = 0; tarjan(i, 0); if (e / 2 >= v + sqrt(v) + 2) { puts("Yes"); return 0; } } } for (int i = 1; i <= m; i++) if (belong[x[i]] == belong[y[i]]) { b[x[i]].insert(y[i]); b[y[i]].insert(x[i]); } for (int i = 1; i <= n; i++) { iskey[i] = b[i].size() >= 3; if (!vis[i]) { v = 0, e = 0, dfs(i); if (e == 2 * v) { ans[v] += 2; if (ans[v] >= 3) { puts("Yes"); return 0; } } } } for (int i = 1; i <= n; i++) if (iskey[i]) { p.push_back(i); while (!b[i].empty()) { int dest = *b[i].begin(); rebuild(i, i, dest, 1); } } for (int i = 1; i <= n; i++) { sort(c[i].begin(), c[i].end()); reverse(c[i].begin(), c[i].end()); } memset(vis, false, sizeof(vis)); for (int i = 1; i <= n; i++) if (iskey[i]) work(i, i, 0); puts("No"); return 0; } // Cheating Solution O(Exp(N)) #include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; const int MAXM = 1e6 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } int n, m, em, v, e, start, ans[MAXN]; int x[MAXM], y[MAXM], p[MAXN], rk[MAXN], rd[MAXN]; vector <int> a[MAXN]; set <int> b[MAXN]; vector <pair <pair <int, int>, int>> c[MAXN]; bool vis[MAXN], vise[MAXN], iskey[MAXN]; bool instack[MAXN]; int tot, belong[MAXN], top, Stack[MAXN]; int timer, dfn[MAXN], low[MAXN]; bool cmp(int x, int y) { if (c[x].size() == c[y].size()) return rd[x] < rd[y]; else return c[x].size() > c[y].size(); } bool cnp(pair <pair <int, int>, int> x, pair <pair <int, int>, int> y) { if (x.first.first == y.first.first) { if (x.second == y.second) return x.first.second < y.first.second; else return x.second < y.second; } else return rk[x.first.first] < rk[y.first.first]; } void tarjan(int pos, int fa) { low[pos] = dfn[pos] = ++timer; v++, e += a[pos].size(); Stack[++top] = pos; instack[pos] = true; for (unsigned i = 0; i < a[pos].size(); i++) { if (a[pos][i] == fa) continue; if (dfn[a[pos][i]] == 0) { tarjan(a[pos][i], pos); low[pos] = min(low[pos], low[a[pos][i]]); } else if (instack[a[pos][i]]) low[pos] = min(low[pos], dfn[a[pos][i]]); } if (low[pos] == dfn[pos]) { int tmp = Stack[top--]; belong[tmp] = ++tot; instack[tmp] = false; while (tmp != pos) { tmp = Stack[top--]; belong[tmp] = tot; instack[tmp] = false; } } } void rebuild(int from, int fa, int pos, int len) { b[fa].erase(pos), b[pos].erase(fa); if (iskey[pos]) { if (from == pos) { ans[len] += 2; if (ans[len] >= 3) { puts("Yes"); exit(0); } return; } c[from].emplace_back(make_pair(pos, len), ++em); c[pos].emplace_back(make_pair(from, len), em); return; } int dest = *b[pos].begin(); rebuild(from, pos, dest, len + 1); } void dfs(int pos) { vis[pos] = true; v++, e += b[pos].size(); for (auto x : b[pos]) if (!vis[x]) dfs(x); } void work(int pos, int from, int depth) { if (depth && pos == from) { if (++ans[depth] >= 3) { puts("Yes"); exit(0); } return; } if ((clock() - start) >= 1.5 * CLOCKS_PER_SEC) { puts("No"); exit(0); } while (!c[pos].empty() && rk[c[pos].back().first.first] < rk[from]) c[pos].pop_back(); for (unsigned i = 0; i < c[pos].size(); i++) { pair <pair <int, int>, int> x = c[pos][i]; if (!vise[x.second] && !vis[x.first.first]) { vise[x.second] = vis[x.first.first] = true; work(x.first.first, from, depth + x.first.second); vise[x.second] = vis[x.first.first] = false; } } } int main() { read(n), read(m), start = clock(); for (int i = 1; i <= m; i++) { read(x[i]), read(y[i]); a[x[i]].push_back(y[i]); a[y[i]].push_back(x[i]); } for (int i = 1; i <= n; i++) { if (dfn[i] == 0) { v = 0, e = 0; tarjan(i, 0); if (e / 2 >= v + sqrt(v) + 2) { puts("Yes"); return 0; } } } for (int i = 1; i <= m; i++) if (belong[x[i]] == belong[y[i]]) { b[x[i]].insert(y[i]); b[y[i]].insert(x[i]); } for (int i = 1; i <= n; i++) { iskey[i] = b[i].size() >= 3; if (!vis[i]) { v = 0, e = 0, dfs(i); if (e == 2 * v) { ans[v] += 2; if (ans[v] >= 3) { puts("Yes"); return 0; } } } } for (int i = 1; i <= n; i++) if (iskey[i]) { while (!b[i].empty()) { int dest = *b[i].begin(); rebuild(i, i, dest, 1); } } for (int i = 1; i <= n; i++) p[i] = i, rd[i] = i; random_shuffle(rd + 1, rd + n + 1); sort(p + 1, p + n + 1, cmp); for (int i = 1; i <= n; i++) rk[p[i]] = i; for (int i = 1; i <= n; i++) { sort(c[i].begin(), c[i].end(), cnp); reverse(c[i].begin(), c[i].end()); } memset(vis, false, sizeof(vis)); for (int i = 1; i <= n; i++) work(p[i], p[i], 0); puts("No"); return 0; }