LA 3523 Knights of the Round Table 边双连通分量+二分图判定

收获:

1、面对在图中分离出一个圈的问题时,要想到用无向图的边双连通分量

2、当强调这个圈满足边数的奇偶条件时,要想到和二分图有关

#pragma warning(disable:4786)
#pragma comment(linker, "/stk:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#include<bitset>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 1e3 + 5;
struct Edge{
    int u,v;
    Edge(int u=0,int v=0):u(u),v(v){}
}edges[maxn * maxn * 2];
int tot;
int n , m , stamp , dfn[maxn] , low[maxn] , iscut[maxn] , bccno[maxn] ;
vector<int> vec[maxn] , bcc[maxn];
int scnt , bcc_cnt , stk[maxn * maxn * 2] , hate[maxn][maxn] , vis[maxn] , color[maxn];
void Add_Edge(int u , int v)
{
    Edge e = Edge(u , v);
    edges[tot] = e;
    vec[u].push_back(tot);
    ++tot;
}
void init()
{
    mem(dfn , 0);   mem(low , 0);
    mem(iscut , 0);     mem(bccno , 0);
    mem(hate , 0);      mem(vis , 0);
    for(int i = 1 ; i <= n ; i++){
        vec[i].clear();
        bcc[i].clear();
    }
    stamp = scnt = bcc_cnt = tot = 0;
}
bool bipartite(int u)
{
    for(int i = 0 ; i < vec[u].size() ; i++){
        int v = edges[vec[u][i]].v;
        if(bccno[v] != bcc_cnt)     continue;
        if(color[v] == color[u])      return false;
        if(!color[v]){
            color[v] = 3 - color[u];
            if(!bipartite(v))       return false;
        }
    }
    return true;
}
void tarjan(int index , int fa)
{
    int child = 0 ;
    dfn[index] = low[index] = ++stamp;
    for(int i = 0 ; i < vec[index].size() ; i++){
        int tmp = edges[vec[index][i]].v;
        if(!dfn[tmp]){
            stk[++scnt] = vec[index][i];
            tarjan(tmp , index);
            low[index] = min(low[index] , low[tmp]);
            if(low[tmp] >= dfn[index]){
                iscut[index] = 1;
                bcc[++bcc_cnt].clear();
                while(1){
                    int num = stk[scnt--];
                    if(bccno[edges[num].u] != bcc_cnt){
                        bcc[bcc_cnt].push_back(edges[num].u);
                        bccno[edges[num].u] = bcc_cnt;
                    }
                    if(bccno[edges[num].v ] != bcc_cnt){
                        bcc[bcc_cnt].push_back(edges[num].v);
                        bccno[edges[num].v] = bcc_cnt;
                    }
                    if(edges[num].u == index && edges[num].v == tmp){
                        break;
                    }
                }
                mem(color , 0);
                color[index] = 1;
                if(!bipartite(index)){
                    for(int k = 0 ; k < bcc[bcc_cnt].size() ; k++){
                        int cur = bcc[bcc_cnt][k];
                        vis[cur] = 1;
                    }
                }
            }
        }
        else  if(dfn[tmp] < dfn[index] && fa != tmp){
            stk[++scnt] = vec[index][i];
            low[index] = min(low[index] , dfn[tmp]);
        }
    }
    if(fa == -1 && child == 1)
        iscut[index] = 0;
}
int main()
{
    int k1  , k2;
    while(scanf("%d %d" , &n , &m) != EOF){
        if(!n && !m)        break;
        init();
        for(int i = 1 ; i <= m ; i++){
            scanf("%d %d" , &k1 , &k2);
            hate[k1][k2] = hate[k2][k1]  = 1;
        }
        for(int i = 1 ; i <= n; i++){
            for(int j = 1 ; j <= n ; j++){
                if(hate[i][j] || i == j)        continue;
                Add_Edge(i , j);
            }
        }
        for(int i = 1 ; i <= n ; i++){
            if(!dfn[i])     tarjan(i , -1);
        }
        int ans = n;
        for(int i = 1 ; i <= n ; i++){
            if(vis[i]) --ans;
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值