poj 2942 奇圈+点双联通分量

/***昨天开了一段时间然后不会。。。今天又看了一上午,虽然不是很彻底,但是最终好事搞定了
真是感觉到心力憔悴。。。。。。。
奇圈:边数为奇数的圈
定理:二分图中不存在奇圈;
***/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace  std;
const int M = 1008;
int low[M],t,dfs[M],instack[M],odd[M],index,bet,cn,stack[M];
int a[M],tmp,number[M],top,color[M],map[M][M];
struct{
    int head;
}H[M];
struct{
    int u,v,next;
}E[M*M*2];
void add(int u,int v)
{
    E[top].v = v;
    E[top].next = H[u].head;
    H[u].head = top++;
}
void init()
{
    memset(map,0,sizeof(map));
    memset(E,-1,sizeof(E));
    memset(H,-1,sizeof(H));
    memset(low,0,sizeof(low));
    memset(dfs,0,sizeof(dfs));
    memset(instack,0,sizeof(instack));
    memset(odd,0,sizeof(odd));
    memset(number,0,sizeof(number));
    tmp = cn = bet = index = top = 0;
}
bool co_cycle ( int u, int clr ) //判断是否存在奇圈
{
    color[u] = clr;
    for ( int i = H[u].head; i!=-1; i = E[i].next )
    {
        int v = E[i].v;
        if ( number[v] == bet )
        {
            if ( color[v] && color[v] == color[u] )
                return true;
            if ( !color[v] && co_cycle (v, -clr) )
                return true;
        }
    }
    return false;
}
void tarjan(int u,int fa)
{
    dfs[u] = low[u] = ++index;
    stack[++cn] = u;
    instack[u] = 1;
    for(int i=H[u].head;i!=-1;i=E[i].next)
    {
        int v = E[i].v;
        if(v == fa)continue;
        if(!dfs[v])
        {
            tarjan(v,u);
            low[u] = min(low[u],low[v]);
            if(low[v]>=dfs[u])
            {
                bet++;
                do
                {
                  t = stack[cn--];
                  instack[t] = 0;
                  a[++tmp] = t;
                  number[t] = bet;  // 类似于强联通分量
                }while(t!=v);

            }
            a[++tmp] = u;
            memset(color,0,sizeof(color));
            if(tmp>=3 && co_cycle(u,1))
            {
                while(tmp)
                    odd[a[tmp--]] = 1;
            }
            else tmp = 0;
        }
        else
            if(instack[v])
            low[u] = min(low[u],dfs[v]);
    }
}
int main()
{
    int n,m;
    int u,v;
    while(~scanf("%d%d",&n,&m),n+m)
    {
        init();
        while(m --)
        {
            scanf("%d%d",&u,&v);
            map[u][v] = map[v][u] = 1;
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)if(!map[i][j]){
            add(i,j);add(j,i);}

            for(int i=1;i<=n;i++)
               if(!dfs[i]) tarjan(i,-1);
           int ans = 0;
           for(int i=1;i<=n;i++)
            if(!odd[i])ans++;
           printf("%d\n",ans);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值