poj2942 Knights of the Round Table(点双的性质+二分图染色)

首先我们建出补图,那么就是求这样的点的个数:不在任何一个>=3的奇环上。
我们搞出点双,如果点x,y不在一个点双内,那么他俩一定不在一个环上。
所以我们对每个点双分别讨论。
这里有一个结论:如果一个点双内存在一个奇环,那么这个点双内的每一个点都在一个奇环上。
大概口胡一下:对于一个点双,一定存在一个过所有点的简单环路。如果这个点双有奇数个点,则得证。
否则如果我们找到了一个奇环。点双内部的环与环之间一定有至少两个公共点,所以这个奇环与大环至少有两个公共点,而这两个公共点把奇环分成了奇数个点/偶数个点的两部分,我们取偶数那部分,再加上剩余的不在奇环上的点则可以构成一个奇环。
因此我们只需要对每一个bcc二分图染色,看是否存在奇环即可。注意对割点的处理qaq
复杂度 O(nm) O ( n m )

#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1010
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,h[N],num,dfn[N],low[N],dfnum,col[N],h1[N],num1,a[N];
bool ok[N],mp[N][N],used[1000010];
struct edge{
    int to,next;
}data[1000010<<1],data1[1000010<<1];
stack<int>qq;
stack<int>qqq;
inline void add(int x,int y){
    data1[++num1].to=y;data1[num1].next=h1[x];h1[x]=num1;
    data1[++num1].to=x;data1[num1].next=h1[y];h1[y]=num1;
}
bool dfs(int x){
    for(int i=h1[x];i;i=data1[i].next){
        int y=data1[i].to;
        if(col[y]!=-1){
            if(col[y]==col[x]) return 1;continue;
        }col[y]=col[x]^1;if(dfs(y)) return 1;
    }return 0;
} 
inline void tarjan(int x){
    dfn[x]=low[x]=++dfnum;qq.push(x);
    for(int i=h[x];i;i=data[i].next){
        int y=data[i].to;if(used[i>>1]) continue;
        used[i>>1]=1;qqq.push(i>>1);
        if(!dfn[y]){
            tarjan(y);low[x]=min(low[x],low[y]);
            if(low[y]continue;m=0;
            while(1){
                int z=qq.top();qq.pop();a[++m]=z;
                if(z==y) break;
            }a[++m]=x;
            while(1){
                int j=qqq.top();qqq.pop();add(data[j<<1].to,data[j<<1|1].to);
                if(j==i/2) break;
            }col[x]=0;if(dfs(x)) for(int i=1;i<=m;++i) ok[a[i]]=1;
            for(int i=1;i<=m;++i) h1[a[i]]=0,col[a[i]]=-1;num1=0;continue;
        }low[x]=min(low[x],dfn[y]);
    }
}
int main(){
//  freopen("a.in","r",stdin);
    while(1){
        n=read();m=read();if(!n&!m) break;memset(h,0,sizeof(h));num=1;memset(dfn,0,sizeof(dfn));dfnum=0;
        memset(col,-1,sizeof(col));memset(ok,0,sizeof(ok));int ans=0;memset(mp,0,sizeof(mp));memset(used,0,sizeof(used));
        while(m--){int x=read(),y=read();mp[x][y]=mp[y][x]=1;}
        for(int x=1;x<=n;++x)
            for(int y=x+1;y<=n;++y){
                if(mp[x][y]) continue;
                data[++num].to=y;data[num].next=h[x];h[x]=num;
                data[++num].to=x;data[num].next=h[y];h[y]=num;
            }
        for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i),qq.pop();
        for(int i=1;i<=n;++i) if(!ok[i]) ++ans;
        printf("%d\n",ans);
    }return 0;
}

你可能感兴趣的:(其他oj,tarjan,二分图)