Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 955 Accepted Submission(s): 284
Problem Description
Ery is interested in graph theory, today he ask BrotherK a problem about it: Given you a undirected graph with X can't be 0)
Input
The first line contains a single integer i
There is at most one edge between any pair of vertex.
There is at most one edge between any pair of vertex.
Output
For each test, print two lines.
The first line contains "YES" or "NO" for question 1.
The second line contains "YES" or "NO" for question 2.
The first line contains "YES" or "NO" for question 1.
The second line contains "YES" or "NO" for question 2.
Sample Input
3
1 0
3 3
1 2
2 3
3 1
4 4
1 2
2 3
3 4
4 1
Sample Output
NO
NO
YES
NO
NO
YES
Hint
If you need a larger stack size,
please use #pragma comment(linker, "/STACK:102400000,102400000") and submit your solution using C++.Source
Recommend
大致题意:给定一个图,问是否存在奇环和偶环.
分析:是否有奇环非常简单,判断一下是不是二分图就可以了.对于偶环的话,题目给的是无向图,无向图上考虑环就先建出dfs树来,找返祖边,如果返祖点到目前点的深度差为奇数,那么环就是偶环,直接就判断完了.如果有多个奇环之间共边,那么就存在偶环.而奇环共边就构成了双连通分量,也就是说要先找到双连通分量,然后在每个双连通分量里找奇环,如果奇环的个数>1,那么就存在偶环.
那么如何找双连通分量?把桥给找出来,桥是一定不在双连通分量里的,因为双连通分量里的任何一条边拿走,其中的点还是连通的,那么不是桥的边就属于双连通分量了.利用tarjan算法找桥.因为是无向图,还要多传递一个参数:父亲节点,并且返祖的时候还要看看终点与起点的深度差.对于每一个点,求出通向它的那条边是谁,反向边就可以通过^1来得到.这样一旦pre[u] = low[u],那么一开始通向u的边就是桥.
无向图的tarjan算法要注意传递父亲节点这个信息.一个技巧:为了准确快速地获得通向当前点u的边在邻接表中的编号以及反向边的编号,可以将head初始化为-1,tot初始化为2.这样^1就是反向边了.
#include <cstdio> #include <cstring> #include <iostream> #include <stack> #include <algorithm> using namespace std; const int maxn = 600010; int n, m, T, head[maxn], to[maxn], nextt[maxn], tot, id[maxn], pre[maxn], low[maxn], scc[maxn], scc_tot; int ans1, ans2, dfs_clock, bridge[maxn], now[maxn], vis[maxn], deep[maxn], f[maxn], sum; stack <int> s; void init() { memset(head, -1, sizeof(head)); memset(id, 0, sizeof(id)); memset(vis, 0, sizeof(vis)); memset(now, 0, sizeof(now)); memset(pre, 0, sizeof(pre)); memset(low, 0, sizeof(low)); memset(f, 0, sizeof(f)); memset(deep, 0, sizeof(deep)); memset(scc, 0, sizeof(scc)); memset(bridge, 0, sizeof(bridge)); sum = 0; scc_tot = 0; tot = 2; ans1 = ans2 = 0; dfs_clock = 0; } void add(int x, int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void tarjan(int u, int fa) { pre[u] = low[u] = ++dfs_clock; s.push(u); for (int i = head[u]; i != -1; i = nextt[i]) { int v = to[i]; if (!pre[v]) { id[v] = (i ^ 1); tarjan(v, u); low[u] = min(low[u], low[v]); } else if (v != fa && pre[v] < pre[u]) low[u] = min(low[u], pre[v]); } if (pre[u] == low[u]) { bridge[id[u]] = bridge[id[u] ^ 1] = 1; while (1) { int t = s.top(); s.pop(); if (t == u) break; } } } void dfs(int u, int depth,int fa) { deep[u] = depth; vis[u] = now[u] = 1; for (int i = head[u]; i != -1; i = nextt[i]) { if (bridge[i]) continue; int v = to[i]; if (!vis[v]) dfs(v, depth + 1,u); else if (now[v] && v != fa) { int temp = depth - deep[v] + 1; if (temp % 2 == 1) { ans1 = 1; sum++; if (sum > 1) ans2 = 1; } else ans2 = 1; } } now[u] = 0; } int main() { scanf("%d", &T); while (T--) { init(); scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); add(u, v); add(v, u); } for (int i = 1; i <= n; i++) if (!pre[i]) tarjan(i, 0); for (int i = 1; i <= n; i++) if (!vis[i]) { sum = 0; dfs(i, 1,0); } printf("%s\n", ans1 ? "YES" : "NO"); printf("%s\n", ans2 ? "YES" : "NO"); } return 0; }