poj 2942 求点双联通+二分图判断奇偶环+交叉染色法判断二分图

http://blog.csdn.net/lyy289065406/article/details/6756821
http://www.cnblogs.com/wuyiqi/archive/2011/10/19/2217911.html

#include "stdio.h"
#include "string.h"

#define N 1010

int time;
int n,m;
bool map[N][N];

struct node
{
    int x,y;
    //int weight;
    bool visit;  //用来标记该边是否已经访问
    int next;
}edge[2*N*N];
int idx,head[N];

bool odd[N];
bool mark[N];  //标记点是否为当前双连通分量中的元素
int low[N],dfn[N];
int st[N*N],top;  //模拟栈
int col[N];

void Read_date();
inline int MIN(int a,int b) { return a<b?a:b; }
void Init(){ idx=0; memset(head,-1,sizeof(head)); }
void Add(int x,int y)
{
    edge[idx].x = x;
    edge[idx].y = y;
    edge[idx].visit = false;
    edge[idx].next = head[x];
    head[x] = idx++;
}

bool find(int x)   //判断当前双连通分量是否为二分图
{
    int i,y;
    for(i=head[x]; i!=-1; i=edge[i].next)
    {
        y = edge[i].y;
        if(mark[y])
        {
            if(col[y]==-1)
            {
                col[y] = !col[x];
                return find(y);
            }
            else if(col[y]==col[x])
                return false;  //不是二分图,返回false
        }
    }
    return true; //是二分图,返回true
}

void Color(int x)
{
    int i;
    memset(mark,false,sizeof(mark));
    while(1)
    {
        i = st[top];
        top--;
        mark[edge[i].x] = true;
        mark[edge[i].y] = true;
        if(edge[i].x==x) break;
    }
    memset(col,-1,sizeof(col));
    col[x] = 0;
    if(!find(x))  //双连通分量不是二分图,则这些点全部可以
    {
        for(i=1; i<=n; ++i)
        {
            if(mark[i])
                odd[i] = 1;
        }
    }
}

void DFS(int x)
{
    int i,y;
    low[x] = dfn[x] = ++time;
    for(i=head[x]; i!=-1; i=edge[i].next)
    {
        y = edge[i].y;
        if(edge[i].visit) continue;
        edge[i].visit = edge[i^1].visit = 1;//走过的边不能再走了
        st[++top] = i;
        if(!dfn[y])
        {
            DFS(y);
            low[x] = MIN(low[x],low[y]);
            if(low[y]>=dfn[x])   //找到割顶或者为根节点
                Color(x);
        }
        else
            low[x] = MIN(low[x],dfn[y]);
    }
}

int Solve()
{
    int i;
    int num=0;
    time = 0;
    top = 0;
    memset(dfn,0,sizeof(dfn));
    memset(odd,false,sizeof(odd));
    for(i=1; i<=n; ++i)
    {
        if(!dfn[i])  //表示点i未被访问过
            DFS(i); //以i为根节点找双连通分量
    }
    for(i=1; i<=n; ++i)
    {
        if(!odd[i])
            num++;
    }
    return num;
}

int main()
{
    while(scanf("%d%d",&n,&m),n||m)
    {
        Read_date();
        printf("%d\n",Solve());
    }
    return 0;
}

void Read_date()
{
    int i,j;
    int x,y;
    memset(map,true,sizeof(map));
    while(m--)
    {
        scanf("%d %d",&x,&y);
        map[x][y] = map[y][x] = false;
    }
    Init();
    for(i=1; i<=n; ++i)
    {
        for(j=i+1; j<=n; ++j)
        {
            if(map[i][j])
            {
                Add(i,j);
                Add(j,i);
            }
        }
    }
}






posted @ 2014-07-20 12:02  HYDhyd  阅读(156)  评论(0编辑  收藏  举报