FZU2181+poj2942(点双连通+判奇圈)

 

分析:我们对于那些相互不憎恨的人连边,将每次参加会议的所有人(不一定是全部人,只需人数>=3且为奇数)看做一个点双联通分量,那么每个点都至少有两个点与他相邻。即需要保证双联通分量中存在奇圈。至于如何判奇圈,这里有一个性质:一个图是二分图当且仅当图中不存在奇圈。至于如何判断一个图是否是二分图,可以采用交替染色的方式判断。

传送门:FZU 2181 快来买肉松饼

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<stack>

using namespace std;

#define MAXN 1005



struct Edge{

    int v,next;

}edge[MAXN*MAXN*2];



int n,m,NE,ans;

int head[MAXN];

bool hate[MAXN][MAXN];

void Insert(int u,int v)

{

    NE++;

    edge[NE].v=v;

    edge[NE].next=head[u];

    head[u]=NE;

}



void Build()

{

    int a,b;

    memset(hate,false,sizeof(hate));

    while(m--){

        scanf("%d%d",&a,&b);

        hate[a][b]=hate[b][a]=true;

    }

    for(int i=1;i<=n;i++){

        for(int j=i+1;j<=n;j++){

            if(!hate[i][j]){

                Insert(i,j);

                Insert(j,i);

            }

        }

    }

}



int cnt,_count;

int low[MAXN],dfn[MAXN];

int block[MAXN];

int color[MAXN];

bool mark[MAXN];

int num[MAXN];

bool is_expelled[MAXN];

stack<int>S;

bool Judge(int u,int state)

{

    color[u]=state;

    for(int i=head[u];i;i=edge[i].next){

        int v=edge[i].v;

        if(block[v]==_count){

            if(color[v]&&color[u]==color[v])

                return true;

            if(!color[v]&&Judge(v,3-state))

                return true;

        }

    }

    return false;

}

void Tarjan(int u,int father)

{

    int flag=0;

    low[u]=dfn[u]=++cnt;

    mark[u]=true;

    S.push(u);

    for(int i=head[u];i;i=edge[i].next){

        int v=edge[i].v;

        if(v==father&&!flag){ flag=1;continue; }

        if(dfn[v]==0){

            Tarjan(v,u);

            low[u]=min(low[u],low[v]);

            if(low[v]>=dfn[u]){

                int x,tmp=0;

                _count++;

                do{

                    x=S.top();

                    S.pop();

                    mark[x]=false;

                    block[x]=_count;

                    num[tmp++]=x;

                }while(x!=v);//割点u可能属于多个连通块,因此不能出栈

                num[tmp++]=u;

                memset(color,0,sizeof(color));

                if(tmp>=3&&Judge(u,1)){

                    while(tmp>0){

                        is_expelled[num[--tmp]]=false;

                    }

                }

            }

        }else if(mark[v]){

            low[u]=min(low[u],dfn[v]);

        }

    }

}

void init()

{

    cnt=_count=0;NE=0;

    memset(head,0,sizeof(head));

    memset(dfn,0,sizeof(dfn));

    memset(low,0,sizeof(low));

    memset(block,0,sizeof(block));

    memset(is_expelled,true,sizeof(is_expelled));

    memset(mark,false,sizeof(mark));

}

int main()

{

    int T,k;

    scanf("%d",&T);

    while(T--){

       // if(n==0&&m==0)break;

        scanf("%d%d%d",&n,&m,&k);

        init();

        Build();

        for(int i=1;i<=n;i++)if(dfn[i]==0)Tarjan(i,-1);

        ans=0;

        for(int i=1;i<=n;i++)if(!is_expelled[i])ans++;

        if(ans>=k)puts("Let's Fire!");

        else puts("What a Pity.");

        //printf("%d\n",ans);

    }

    return 0;

}
View Code

传送门:poj 2942 Knights of the Round Table

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<stack>

using namespace std;

#define MAXN 1005



struct Edge{

    int v,next;

}edge[MAXN*MAXN*2];



int n,m,NE,ans;

int head[MAXN];

bool hate[MAXN][MAXN];

void Insert(int u,int v)

{

    NE++;

    edge[NE].v=v;

    edge[NE].next=head[u];

    head[u]=NE;

}



void Build()

{

    int a,b;

    memset(hate,false,sizeof(hate));

    while(m--){

        scanf("%d%d",&a,&b);

        hate[a][b]=hate[b][a]=true;

    }

    for(int i=1;i<=n;i++){

        for(int j=i+1;j<=n;j++){

            if(!hate[i][j]){

                Insert(i,j);

                Insert(j,i);

            }

        }

    }

}



int cnt,_count;

int low[MAXN],dfn[MAXN];

int block[MAXN];

int color[MAXN];

bool mark[MAXN];

int num[MAXN];

bool is_expelled[MAXN];

stack<int>S;

bool Judge(int u,int state)

{

    color[u]=state;

    for(int i=head[u];i;i=edge[i].next){

        int v=edge[i].v;

        if(block[v]==_count){

            if(color[v]&&color[u]==color[v])

                return true;

            if(!color[v]&&Judge(v,3-state))

                return true;

        }

    }

    return false;

}

void Tarjan(int u,int father)

{

    int flag=0;

    low[u]=dfn[u]=++cnt;

    mark[u]=true;

    S.push(u);

    for(int i=head[u];i;i=edge[i].next){

        int v=edge[i].v;

        if(v==father&&!flag){ flag=1;continue; }

        if(dfn[v]==0){

            Tarjan(v,u);

            low[u]=min(low[u],low[v]);

            if(low[v]>=dfn[u]){

                int x,tmp=0;

                _count++;

                do{

                    x=S.top();

                    S.pop();

                    mark[x]=false;

                    block[x]=_count;

                    num[tmp++]=x;

                }while(x!=v);//割点u可能属于多个连通块,因此不能出栈

                num[tmp++]=u;

                memset(color,0,sizeof(color));

                if(tmp>=3&&Judge(u,1)){

                    while(tmp>0){

                        is_expelled[num[--tmp]]=false;

                    }

                }

            }

        }else if(mark[v]){

            low[u]=min(low[u],dfn[v]);

        }

    }

}

void init()

{

    cnt=_count=0;NE=0;

    memset(head,0,sizeof(head));

    memset(dfn,0,sizeof(dfn));

    memset(low,0,sizeof(low));

    memset(block,0,sizeof(block));

    memset(is_expelled,true,sizeof(is_expelled));

    memset(mark,false,sizeof(mark));

}

int main()

{

    while(scanf("%d%d",&n,&m)>0){

        if(n==0&&m==0)break;

        init();

        Build();

        for(int i=1;i<=n;i++)if(dfn[i]==0)Tarjan(i,-1);

        ans=0;

        for(int i=1;i<=n;i++)if(is_expelled[i])ans++;

        printf("%d\n",ans);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(poj)