HDU 5215 Cycle(判定无向图奇偶环)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5215

 

题意:给一个无向图,判断是不是有奇环和偶环

 

思路:如果对于奇环,二分图染色可以判定;

对于偶环,先分离出所有双连通分量,对于一个双联通分量,除非它仅仅由一个奇环组成,否则两个奇环可以通过公用边或点即可组成偶环。

还看到了二分图直接判奇偶环的方法,存个模板。

 

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;

const int MAXN = 100010;
const int MAXM = 300010;

struct Edge
{
    int to, next;
    bool cut;
} edge[MAXM << 1];

int head[MAXN], tot;
int Low[MAXN], DFN[MAXN], Stack[MAXN], Belong[MAXN];
int Index, top, block;
bool Instack[MAXN];
int bridge;

void addedge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    edge[tot].cut = false;
    head[u] = tot++;
}

void Tarjan(int u, int pre)
{
    int v;
    Low[u] = DFN[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if (v == pre)continue;
        if (!DFN[v])
        {
            Tarjan(v, u);
            if (Low[u] > Low[v])
                Low[u] = Low[v];
            if (Low[v] > DFN[u])
            {
                bridge++;
                edge[i].cut = true;
                edge[i ^ 1].cut = true;
            }
        }
        else if (Instack[v] && Low[u] > DFN[v])
            Low[u] = DFN[v];
    }
    if (Low[u] == DFN[u])
    {
        block++;
        do
        {
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = block;
        } while (v != u);
    }
}

void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}


void solve(int n)
{
    memset(DFN, 0, sizeof(DFN));
    memset(Instack, false, sizeof(Instack));
    bridge = Index = top = block = 0;
    for (int i = 1; i <= n; i++)
        if (!DFN[i])
            Tarjan(i, i);
}

int num;
int vis[MAXN], dep[MAXN], cnt[MAXN];
bool odd, even;

void dfs(int u, int depth, int pre)
{
    vis[u] = 1;
    dep[u] = depth;
    cnt[u] = 1;
    for (int i = head[u]; ~i; i = edge[i].next)
    {
        if (edge[i].cut) continue;
        int v = edge[i].to;
        if(v == pre) continue;
        if (vis[v])
        {
            if (cnt[v])
            {
                int len = dep[u] - dep[v] + 1;
                if (len % 2 == 1)
                {
                    odd = true;
                    num++;
                    if (num > 1)
                        even = true;
                }
                else
                    even = true;
            }
        }
        else
            dfs(v, depth + 1, u);
    }
    cnt[u] = 0;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        init();
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            addedge(u, v);
            addedge(v, u);
        }
        solve(n);

        odd = even = false;
        memset(vis, 0, sizeof(vis));
        memset(cnt, 0, sizeof(cnt));
        for (int i = 1; i <= n; i++)
        {
            if (!vis[i])
            {
                num = 0;
                dfs(i, 1, -1);
            }
        }

        printf("%s\n", odd ? "YES" : "NO");
        printf("%s\n", even ? "YES" : "NO");
    }
    return 0;
}

 

 

 

 

 

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <climits>
#include <functional>
#pragma comment(linker, "/STACK:102400000,102400000")

using namespace std;

const int MAXN = 100010;
const int MAXM = 300010;

int head[MAXN], vis[MAXN], cnt;
bool odd, even;

struct edge
{
    int to, nxt, vis;
} e[MAXM << 1];

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
    memset(vis, -1, sizeof(vis));
    for (int i = 0; i < MAXM * 2; i++)
        e[i].vis = 0;
}

void add(int u, int v)
{
    e[cnt].to = v;
    e[cnt].nxt = head[u];
    head[u] = cnt++;
}

void dfs(int u, int fa)
{
    for (int i = head[u]; ~i; i = e[i].nxt)
    {
        int v = e[i].to;
        if (v == fa) continue;
        if (vis[v] != -1)
        {
            if (vis[v] == vis[u])
                odd = true;
            else
                even = true;
        }
        if (!e[i].vis)
        {
            e[i].vis = 1;
            vis[v] = vis[u] ^ 1;
            dfs(v, u);          
        }
    }
    vis[u] = -1;    
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        init();
        int n, m;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }

        odd = even = false;
        for (int i = 1; i <= n; i++)
        {
            if (vis[i] == -1)
            {
                vis[i] = 0;
                dfs(i, 0);
            }
        }

        printf("%s\n", odd ? "YES" : "NO");
        printf("%s\n", even ? "YES" : "NO");
    }
    return 0;
}

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值