图论- hdu5215 Cycle

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=5215

题意:

给一个无向图,无自环,无重边,问图中是否存在边数为奇数与偶数的环

思路:

二分图染色可以解决奇环,但偶环没办法直接处理

考虑到所有的环都出现在双连通子图中,用tarjan算法找出图中所有的桥,删掉

再对每个双连通子图单独染色,若在一个子图中出现了两个以上的奇环,则该图必然存在偶环


如上图,若a+b+c为一个奇环,c+d+e为另一个奇环,则a+b+d+e=(a+b+c)+(c+d+e)-c*2=奇数+奇数-偶数=偶数,必然为一个偶环


代码:

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int maxsize=100000+5;

struct node{
    int u,father;
};

vector<int> adjList[maxsize];
int dfn[maxsize],low[maxsize];
int color[maxsize];
bool isOdd,isEven;
int sum,odd;
queue<node> q;

int index;
void tarjan(int u,int father){

    dfn[u]=low[u]=++index;
    for (vector<int>::iterator it=adjList[u].begin();it!=adjList[u].end();++it){
        int v=*it;
        if (!dfn[v]){
            tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if (dfn[u]<low[v]){
                *it=0;
                for (vector<int>::iterator itv=adjList[v].begin();itv!=adjList[v].end();++itv)
                    if (*itv == u) {*itv=0;break;}
            }
        }
        else if (father!=v) {
            low[u]=min(low[u],dfn[v]);
        }
    }
    return;
}

void colorate(node t){
    color[t.u]=1;
    q.push(t);
    sum++;
    while (!q.empty()){
        node x=q.front();
        q.pop();
        //  cout<<"col:"<<"u color "<<x.u<<" "<<color[x.u]<<" father: "<<x.father<<" size: "<<adjList[x.u].size()<<endl;
        for (vector<int>::iterator it=adjList[x.u].begin();it!=adjList[x.u].end();++it){
            int v=*it;
            //cout<<v<<" "<<color[v]<<endl;
            if ( v==0 || v==x.father) continue;
            for (vector<int>::iterator itv=adjList[v].begin();itv!=adjList[v].end();++itv)
                if (*itv == x.u) {*itv=0;break;}
            if (color[v]==0){
                color[v]=3-color[x.u];
                q.push({v,x.u});
                sum++;
            }
            else if (color[v]==3-color[x.u]){
                isEven=true;
            }
            else if (color[v]=color[x.u]){
                isOdd=true;
                odd++;
                if (odd>1) isEven=true;
            }
        }
    }
    return ;
}


int main(){
    int total;
    cin>>total;
    while (total--){
        int n,m;
        cin>>n>>m;
        for (int i=1;i<=n;++i) adjList[i].clear();

        for (int i=1;i<=m;++i){
            int a,b;
            scanf("%d %d",&a,&b);
            adjList[a].push_back(b);
            adjList[b].push_back(a);
        }

        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        index=0;
        tarjan(1,0);

//        for (int i=1;i<=n;++i){
//            cout<<i<<": ";
//            for (int j=0;j<adjList[i].size();++j){
//                cout<<adjList[i][j]<<" ";
//            }
//            cout<<endl;
//        }

        memset(color,0,sizeof(color));
        //1,2;
        isOdd=false;isEven=false;
        sum=0;
        while (sum<n){
            for (int i=1;i<=n;++i){
                if (color[i]==0){
                    odd=0;
                    colorate({i,0});
                }
            }
        }
        if (isOdd) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
        if (isEven) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值