「题解」:[POJ2942]Knights of the Round Table

问题 E: Knights of the Round Table

时间限制: 1 Sec  内存限制: 256 MB

题面


题目描述

作为一名骑士是一个非常有吸引力的职业:寻找圣杯,拯救遇难的少女,与其他骑士一起喝酒是有趣的事情。因此,近年来亚瑟王国经历了骑士人数空前增加,这并不奇怪。现在有这么多骑士,每个圆桌骑士都可以同时来到卡米洛特并坐在圆桌旁;通常只有一小群骑士在那里,而其他人则忙于在全国各地做英雄事迹。

在讨论中,骑士很容易过度兴奋 - 特别是在喝了几杯酒之后。在发生一些不幸的事故之后,亚瑟王要求着名的精灵梅林确保将来不会在骑士之间爆发战斗。在仔细研究了这个问题之后,Merlin意识到只有骑士按照以下两条规则坐下才能防止战斗:
骑士应该坐着,这样两个相互仇恨的骑士不应该是桌子上的邻居。 (梅林有一个清单,上面写着谁讨厌谁。)骑士围坐在圆桌会议上,因此每个骑士都有两个邻居。
奇数骑士应坐在桌子周围。这确保了如果骑士无法就某事达成一致,那么他们可以通过投票解决问题。 (如果骑士的数量是偶数,则可以发生“是”和“否”具有相同的投票数,并且论证继续进行。)
只有满足这两条规则,梅林才会让骑士坐下来,否则他会取消会议。 (如果只有一个骑士出现,那么会议也会被取消,因为一个人不能坐在桌子旁。)Merlin意识到这意味着骑士不能参加任何符合这些规则的座位安排,并且这些骑士永远无法坐在圆桌会议上(如果一个骑士讨厌其他所有骑士,就会出现这种情况,但还有很多其他可能的原因)。如果骑士不能坐在圆桌会议上,那么他就不能成为圆桌骑士团的成员,必须从骑士团中被驱逐出去。这些骑士必须转移到一个不那么有声望的秩序,如方桌骑士团,八角桌骑士团或香蕉形桌骑士团。为了帮助Merlin,你必须编写一个程序来确定必须被驱逐的骑士数量。

输入格式

输入包含几组测试数据。 每种情况都以包含两个整数1≤n≤1000且1≤m≤1000000的整数行开始。 数字n是骑士的数量。 接下来的m行描述哪个骑士讨厌哪个骑士。 这m行中的每一行包含两个整数k1和k2,这意味着骑士数k1和骑士数k2彼此讨厌(数字k1和k2在1和n之间)。
输入由n = m = 0的块终止。

输出格式

对于每组测试数据,您必须在单独的行上输出一个整数:必须被驱逐的骑士数量。

题解


读题发现,题目要求坐在一起的骑士不能相互仇恨。

假如我们给每一对相互仇恨的骑士建边的话,我们需要找出相互之间没有连边的骑士。

这样似乎十分难处理。于是我们建补图(原先有边变无边,无边变有边)。

所以我们需要求出点双。

题目中还有这样一句话“奇数骑士应坐在桌子周围”,所以找奇环,用黑白染色法。(我染的点,听说有大神染的边)

主要要注意的是割点的处理。我们每次把属于该点双的全打上标记就可以了。如果在求点双里直接打标记的话,割点会被多个点双重复标记,处理起来很麻烦。

细节要处理好。

还有,多判要清空哦~

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<stack>
#define rint register int
using namespace std;
struct node{int u,v,nxt;}edge[2000006],edgec[2000006];
int n,m,k1,k2,toty,firsty[1003],dfn[1003],firstc[1003];
int low[1003],cnt,root,newid[1003],totq,totc,c[1003],ans;
int belong[1003],color[1003];
bool map[1003][1003],cut[1003],vis[1003];
stack <int> s;vector <int> dcc[1003];
inline void renew()
{
    toty=cnt=root=totq=totc=ans=0;
    for(rint i=1;i<=n;++i)
        firsty[i]=dfn[i]=firstc[i]=low[i]=newid[i]=c[i]=belong[i]=0,
        color[i]=-1,cut[i]=vis[i]=false;
    for(rint i=1;i<=m;++i)edge[i].u=edge[i].v=edge[i].nxt=edgec[i].u=edgec[i].v=edgec[i].nxt=0;
    memset(map,false,sizeof(map));
}
inline void build_line(int uu,int vv)
{
    ++toty;edge[toty].u=uu;edge[toty].v=vv;
    edge[toty].nxt=firsty[uu];firsty[uu]=toty;
}
inline void add(int uu,int vv)
{
    ++totc;edgec[totc].u=uu;edgec[totc].v=vv;
    edgec[totc].nxt=firstc[uu];firstc[uu]=totc;
}
inline void tarjan(int x)
{
    dfn[x]=low[x]=++cnt;s.push(x);
    if(x==root && firsty[x]==0)
    {
        dcc[++totq].clear();
        dcc[totq].push_back(x);
        return ;
    }
    int flag=0;
    for(rint i=firsty[x];i;i=edge[i].nxt)
    {
        int y=edge[i].v;
        if(!dfn[y])
        {
            tarjan(y);low[x]=min(low[x],low[y]);
            if(low[y]>=dfn[x])
            {
                flag++;
                if(x!=root||flag>1)cut[x]=true;
                totq++;int z;
                dcc[totq].clear();
                do{
                    z=s.top();s.pop();
                    dcc[totq].push_back(z);
                }while(z!=y);
                dcc[totq].push_back(x);
            }
        }
        else low[x]=min(low[x],dfn[y]);
    }
}
inline bool dfs(int x,int last)
{
    color[x]=color[last]^1;
    for(rint i=firsty[x];i;i=edge[i].nxt)
    {
        int y=edge[i].v;
        if(!belong[y]||y==last)continue;
        if(color[y]!=-1&&color[y]==color[x])return true;
        if(color[y]==-1&&dfs(y,color[x]))return true;
    }
    return false;
}
int main()
{
    while(1)
    {
        scanf("%d %d",&n,&m);
        if(n==0&&m==0)return 0;
        renew();
        for(rint i=1;i<=m;++i)
        {
            scanf("%d %d",&k1,&k2);
            map[k1][k2]=map[k2][k1]=1;
        }
        for(rint i=1;i<=n;++i)
            for(rint j=i+1;j<=n;++j)
                if(!map[i][j]) build_line(i,j),build_line(j,i);
        for(rint i=1;i<=n;++i)
            if(!dfn[i])root=i,tarjan(i);
        color[0]=0;
        for(rint i=1;i<=totq;++i)
        {
            for(rint j=0;j<dcc[i].size();++j)
                belong[dcc[i][j]]=1;
            if(dfs(dcc[i][0],0))
                for(rint j=0;j<dcc[i].size();++j)
                    vis[dcc[i][j]]=true;
            for(rint j=0;j<dcc[i].size();++j)
            {
                if(cut[dcc[i][j]])
                    color[dcc[i][j]]=-1;
                belong[dcc[i][j]]=0;
            }
        }
        for(rint i=1;i<=n;++i)
            if(vis[i])ans++;
        ans=n-ans;printf("%d\n",ans);
    }
    return 0;
}
View Code
posted @ 2019-07-18 17:09  hzoi_Joe  阅读(485)  评论(0编辑  收藏  举报