• 「题解」:[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
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    详解Winform多线程编程基本原理
    asp.net 文件夹和文件的创建、删除
    sql server 查询表名,存储过程,列名等
    随机输出数组中的一个数
    C# 获取Access数据库中所有表名及其列名、列类型
    Oracle 数据库小记
    Oracle11g、PLSQL、Winfrom环境搭建
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
    Android开发中用到的框架、库介绍
    Android数据存储
  • 原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11208570.html
Copyright © 2020-2023  润新知