POJ 2942 Knights of the Round Table

为了校赛 特地去学图论,刚搞到双联通分量,就弄这么一道神题出来,,,

据小优说她同学搞了4个月,她搞了2天。。。

嘛,我是看了人家的题解,拿着别人的模版,搞了一下午= = 。。。其实自己的东西用到的很少啊。。。


首先把原图搞成补图,注意补图中不要有自环= =。。

把所有双联通分量搞出来,对于每一个双联通分量判断是否是二分图,

不是的话,把双联通分量里面的点标记上就好了。。。

最后计算未标记的点的个数=n-标记的个数。。。

代码

#include<cstdio>
#include<vector>
#define X 1010
using namespace std;
bool map[X][X];
vector<int>edge[X];
vector<vector<int> >connect;
int dfn[X],low[X],in_seq[X];
int stack[X],list[X],as[X];
int cnt,top,pop,len;
void biconnect(int v){
    stack[++top]=v;
    dfn[v]=low[v]=pop++;
    int i,succ;
    for(i=edge[v].size()-1;i>=0;i--){
        succ=edge[v][i];
        if(dfn[succ]==-1){
            biconnect(succ);
            if(low[succ]>=dfn[v]){
                cnt++;len=0;
                do{
                    in_seq[stack[top]]=cnt;
                    list[len++]=stack[top];
                    top--;
                }while(stack[top+1]!=succ);
                in_seq[v]=cnt;
                list[len++]=v;
                vector<int> tmp(list,list+len);
                connect.push_back(tmp);
            }
            low[v]=min(low[v],low[succ]);
        }
        else low[v]=min(low[v],dfn[succ]);
    }
}
bool flag,bif[X];
int vis[X];
void dfs(int u,int e){
    int v,i,n=edge[u].size();
    vis[u]=e+1;
    for(i=0;i<n&&flag;i++){
        v=edge[u][i];
        if(bif[v]){
            if(vis[v]==vis[u])
                flag=0;
            if(!vis[v])dfs(v,!e);
        }
    }
}
void make(vector<int> v){
    int i,j,n;
    n=v.size();flag=1;
    if(n<3)return ;
    for(i=0;i<n;i++)
        bif[v[i]]=1;
    dfs(v[0],0);
    if(!flag)for(i=0;i<n;i++)as[v[i]]=1;
}
int main(){
    int i,j,n,m,u,v;
    while(scanf("%d%d",&n,&m),n||m){
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                map[i][j]=i!=j;
        for(i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            map[u][v]=0;
            map[v][u]=0;
        }
        connect.clear();
        cnt=top=pop=len=0;
        for(i=1;i<=n;i++){
            dfn[i]=-1;
            as[i]=0;
            edge[i].clear();
        }
        for(i=1;i<=n;i++)
            for(j=1;j<=n;j++)
                if(map[i][j])
                    edge[i].push_back(j);
        for(i=1;i<=n;i++)
            if(dfn[i]==-1)
                biconnect(i);
        for(i=0;i<connect.size();i++){
            for(j=1;j<=n;j++)vis[j]=bif[j]=0;
            make(connect[i]);
        }
        m=n;
        for(i=1;i<=n;i++)m-=as[i];
        printf("%d\n",m);
    }
    return 0;
}



你可能感兴趣的:(二分图,双联通分量)