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;
}

传送门: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;
}

时间: 2024-08-24 08:19:47

FZU2181+poj2942(点双连通+判奇圈)的相关文章

poj 2942 Knights of the Round Table 【双连通缩点+判奇圈】【经典】

题目:poj 2942 Knights of the Round Table 题意:n个骑士经常一起开会,其中有一些两两相互憎恨,他们不能同一桌,开会要表决一些事情,所以必须奇数个人,最少3个,求永远也参加不了会议的人的个数. 分析:这个题目两点 首先,建图求双连通缩点 建图的话,因为相互憎恨的不能再一块,所以要建补图,让能够在一起的所有的连接,这样的话,如果能存在环且环上的点是奇数个的话就可以参加会议,标记求不能参加的即可. 建好图之后用tarjan算法双连通缩点,把在一个环上的点保存起来.

poj2942圆桌骑士(点双连通分量+二分图染色法判奇圈)

之前一直不明白点双连通分量能用来干嘛,比如边双连通分量可以问加几条边能变成边双连通,这个题目是这样的,每个圆桌会议至少三个骑士参加,因为需要表决意见,所以骑士数目必须是奇数个,直到那些骑士互相憎恨,也就是不能坐在一起的,把能坐在一起的建边,求无法参加任何会议的骑士的个数,重点是任何会议,这点非常关键,这道题之前一直卡在这里,还有就是有的人属于好几种双连通分量,所以全部标记之后再减掉比较好,至于奇数个怎么处理呢,今天才知道原来二分图的判断可以解决奇圈的问题,因为如果是二分图的话,我们染色,相邻的涂

fzu2181(点的双连通分量+求奇环)

求出每个点双连通分量,如果在一个点双连通分量中有奇环,则这个分量每个点都在一个奇环中.  关键是要知道怎么求点双连通分量以及点双连通的性质. fzu2181 http://acm.fzu.edu.cn/problem.php?pid=2181 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define

POJ2942 Knights of the Round Table 点双连通分量,逆图,奇圈

题目链接: poj2942 题意: 有n个人,能够开多场圆桌会议 这n个人中,有m对人有仇视的关系,相互仇视的两人坐在相邻的位置 且每场圆桌会议的人数仅仅能为奇书 问有多少人不能參加 解题思路: 首先构图,将全部的仇视关系视为一条边,最后再取已经得到的图的逆图, 这样图上连接的边就代表能够相邻而坐的关系 然后就是找奇圈了,首先就是要找图中的环(点双连通分量) 这个环为奇环的条件:不是二分图||这个环中的部分点属于其它奇环 这个推断能够通过将已找到的环进行dfs黑白染色推断 最后不在奇环内的总和即

【POJ 2942】Knights of the Round Table(双联通分量+染色判奇环)

[POJ 2942]Knights of the Round Table(双联通分量+染色判奇环) Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 11661   Accepted: 3824 Description Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress, an

双连通

poj 3352 Road Construction && poj 3177 Redundant Paths 给一个无向图,问最少需要添加多少条边,使它成为双连通图. 做法:边双连通缩点,成为一棵树.若要使得任意一棵树,变成一个双连通图,那么至少增加的边数 =(度数为1的结点数 + 1 )/ 2 1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 #include<cstdio

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful(双连通)

HDU 3849 By Recognizing These Guys, We Find Social Networks Useful 题目链接 题意:说白了就是求一个无向图的桥 思路:字符串hash掉,然后双连通.要注意特判一下假设不是一个连通块.那么答案是0 代码: #include <cstdio> #include <cstring> #include <string> #include <vector> #include <map> us

UVA 1364 - Knights of the Round Table(双连通+二分图判定)

UVA 1364 - Knights of the Round Table 题目链接 题意:有n个圆桌骑士,知道一些骑士互相憎恨,现在要开圆桌会议,每次最少3个人,必须是奇数人数,并且互相憎恨的骑士不能在相邻,问有多少骑士是一次都无法参加的 思路:把每个骑士可以相邻的连边,然后做双连通分量,然后对于每个连通分量,利用二分图染色判定去判断是否是奇圈 代码: #include <cstdio> #include <cstring> #include <vector> #in

ZOJ 2588 Burning Bridges 求无向图桥 边双连通裸题

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1588 binshen的板子: #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #i