码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-02-13 00:09:20      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:

 

分析:我们对于那些相互不憎恨的人连边,将每次参加会议的所有人(不一定是全部人,只需人数>=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

 

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

标签:

原文地址:http://www.cnblogs.com/lienus/p/4289390.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!