HDU 5215 BestCoder"杯中国大学生程序设计冠军赛” 边双连通分量取出子图+二分染色判图内奇偶环...

Cycle

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 865    Accepted Submission(s): 241


Problem Description
Ery is interested in graph theory, today he ask BrotherK a problem about it: Given you a undirected graph with  N vertexes and  M edges, you can select a vertex as your starting point, then you need to walk in the graph along edges. However, you can't pass a edge more than once, even opposite direction is forbidden. At the end, you should come back to the starting point. Assume you has passed  X edges, there are two questions:

Question 1: Can  X be a odd number ?

Question 2: Can  X be a even number ?

(note: you must walk, so  X can't be 0)
 

 

Input
The first line contains a single integer  T, indicating the number of test cases.

Each test case begins with two integer  N, M, indicating the number of vertexes and the number of edges. Following  M lines, each line contains two integers  Ui, Vi, indicating there are a edge between vertex  Ui and vertex  Vi.

T is about 30

1  N  100000

0  M  300000

1  Ui,Vi  N

Ui will not equal to  Vi

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.
 

 

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
 

题目大意:给你一个有n个顶点的无向图和m条边,从任意一点出发(经过的边不能再经过),问能否通过走偶数步或者奇数步再回到原点。

思路:首先我们用边双连通分量把所有的符合条件的极大子图都给取出来,然后我们分别对极大子图进行求解。边双连通分量有个特性,不存在和其他的子图有公共点或者公共边。所以我们每次都只要考虑当前子图内部即可。接下来进行分类讨论:

①如果只有一个偶环,或者全都是偶环,那么就是偶数步。 ②如果只有一个奇环,那么就只能走奇数步。③如果子图内有多个奇环或子图内奇偶环都有,那么偶数and奇数都可以。

因此,奇偶环的判定我们就用二分图染色,即可以得到偶环和奇环,并且我们得到奇环以后让cnt++即可,并且不进行return即可。

  1 //看看会不会爆int! 或者绝对值问题。
  2 #include <bits/stdc++.h>
  3 using namespace std;
  4 #pragma comment(linker,"/STACK:102400000,102400000")
  5 #define LL long long
  6 #define pb push_back
  7 #define mk make_pair
  8 #define fi first
  9 #define se second
 10 #define all(a) a.begin(), a.end()
 11 const int maxn = 100000 + 5;
 12 vector<int> G[maxn], bcc[maxn];
 13 int bccno[maxn], pre[maxn], low[maxn];
 14 int n, m, dfstime, bcc_cnt;
 15 stack<int> s;
 16 
 17 void dfs(int u, int fa){
 18     low[u] = pre[u] = ++dfstime;
 19     int len = G[u].size();
 20     s.push(u);
 21     for (int i = 0; i < len; i++){
 22         int v = G[u][i];
 23         if (pre[v] == -1){
 24             dfs(v, u);
 25             low[u] = min(low[u], low[v]);
 26         }
 27         else if(bccno[v] == 0){
 28             low[u] = min(low[u], pre[v]);
 29         }
 30     }
 31     if (low[u] == pre[u]){
 32         bcc_cnt++;
 33         while (true){
 34             int x = s.top(); s.pop();
 35             bccno[x] = bcc_cnt;
 36             bcc[bcc_cnt].pb(x);
 37             if (x == u) break;
 38         }
 39     }
 40     return ;
 41 }
 42 int color[maxn], vis[maxn], myodd, myeven;
 43 bool flag;
 44 void draw(int u, int fa){
 45     int len = G[u].size();
 46     for (int i = 0; i < len; i++){
 47         int v = G[u][i];
 48         if (bccno[v] != bccno[u]) continue;
 49         if (color[v] != -1){
 50             if (v == fa) continue;
 51             if (color[u] == color[v]) {
 52                 myodd++;
 53             }
 54             else myeven = 1;
 55         }
 56         else {
 57             color[v] = 1 - color[u];
 58             draw(v, u);
 59         }
 60     }
 61     return ;
 62 }
 63 
 64 int main(){
 65     int t; cin >> t;
 66     while (t--){
 67         scanf("%d%d", &n, &m);
 68         for (int i = 1; i <= n; i++) G[i].clear(), bcc[i].clear();
 69         for (int i = 1; i <= m; i++){
 70             int u, v; scanf("%d%d", &u, &v);
 71             G[u].pb(v), G[v].pb(u);
 72         }
 73         memset(bccno, 0, sizeof(bccno));
 74         memset(pre, -1, sizeof(pre));
 75         memset(low, -1, sizeof(low));
 76         dfstime = bcc_cnt = 0;
 77         for (int i = 1; i <= n; i++){
 78             if (pre[i] == -1){
 79                 dfs(i, -1);
 80             }
 81         }
 82         memset(color, -1, sizeof(color));
 83         ///如果能染色,表示是偶环,反之存在奇环
 84         int odd = 0, even = 0;
 85         for (int i = 1; i <= bcc_cnt; i++){
 86             if (bcc[i].size() > 1){
 87                 myodd = myeven = 0;
 88                 color[bcc[i][0]] = 0;
 89                 draw(bcc[i][0], -1);
 90                 myodd /= 2;
 91                 if (myeven == 1) even = 1;
 92                 if (myodd == 1) odd = 1;
 93                 if (myodd > 1) even = odd = 1;
 94             }
 95             if (odd == 1 && even == 1) break;
 96         }
 97         printf("%s\n", odd ? "YES" : "NO");
 98         printf("%s\n", even ? "YES" : "NO");
 99     }
100     return 0;
101 }
102 
103 /*
104 100
105 7 8
106 1 2
107 2 3
108 1 3
109 2 4
110 4 5
111 5 6
112 6 7
113 7 4
114 
115 ans:
116 yes yes
117 yes yes
118 */
View Code

学习点:对边连通分量的实际意义的使用

转载于:https://www.cnblogs.com/heimao5027/p/5817899.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值