• Knights of the Round Table点双连通分量+奇环


    Knights of the Round Table

    Solution:

    若两人之间无限制,则连一条无向边。

    引理一:

    如果两个人处于不同的点双连通分量,则两人不能同时参与一场会议。
    

    这意味着: 我们可以单独考虑每一个点双联通分量。

    引理二:

    某个人能够参与会议,当且仅当它位于至少一个奇环上。
    

    这意味着:我们只需要统计有多少个点不被任何奇环包含。

    引理三:

    一个点双连通分量中,若存在一个奇环,则所有的点都被至少一个奇环包含。否则所有点不被任何奇环包含。
    

    证明如下:

    对于点双中存在的一个奇环,它肯定由一部分长度为奇数,和一部分长度为偶数的路径组成。
    
    那么,对于非环上的点,它必然至少被包含在两个环上,其中一个为奇环,一个为偶环。
    

    证毕。

    所以直接把对一个v-DCC进行dfs染色,按照二分图判定的方式来判定。

    Code↓:

    #include<string>
    #include<cstdio>
    #include<cstring>
    #define RG register
    #define IL inline
    #define LL long long
    #define DB double
    using namespace std;
    
    IL int gi() {
        char ch=getchar(); RG int x=0,w=0;
        while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
        while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
        return w?-x:x;
    }
    
    const int N=1010;
    const int M=1e6+10;
    
    int n,m,sum,top,cnt,tot,Time,a[N][N],head[N],ST[N],OK[N],dfn[N],low[N],sta[N],bel[N],col[N];
    
    struct VER{int x,y;}In[M];
    struct EDGE{int next,to;}e[M<<1];
    
    IL void make(int x,int y) {
        e[++tot]=(EDGE){head[x],y},head[x]=tot;
        e[++tot]=(EDGE){head[y],x},head[y]=tot;
    }
    
    IL bool dfs(int x,int color,int id) {
        RG int i,y;
        col[x]=color;
        for (i=head[x];i;i=e[i].next) {
            y=e[i].to;
            if (bel[y]!=id) continue;
            if (!col[y]) {
                if (dfs(y,3-color,id)) return 1;
            }
            else if (col[y]==color) return 1;
        }
        return 0;
    }
    
    void Tarjan(int x) {
        RG int i,j,y,now,num=0;
        dfn[x]=low[x]=++Time,sta[++top]=x;
        for (i=head[x];i;i=e[i].next) {
            if (!dfn[y=e[i].to]) {
                Tarjan(y),low[x]=min(low[x],low[y]);
                if (low[y]>=dfn[x]) {
                    ++cnt;
                    do {
                        now=sta[top--],bel[now]=cnt,ST[++num]=now;
                    }while(now!=y);
                    bel[x]=cnt,ST[++num]=x;
                    if (dfs(ST[1],1,cnt))
                        for (j=1;j<=num;++j) OK[ST[j]]=1;
                    for (;num;--num) col[ST[num]]=0;
                }
            }
            else low[x]=min(low[x],dfn[y]);
        }
    }
    
    int main()
    {
        RG int i,j,x,y;
        n=gi(),m=gi();
        while(n&&m) {
            for (i=1;i<=m;++i) {
                x=In[i].x=gi(),y=In[i].y=gi();
                a[x][y]=a[y][x]=1;
            }
            memset(&e,0,sizeof(e));
            memset(head,0,sizeof(head));
            for (i=1,tot=0;i<=n;++i)
                for (j=i+1;j<=n;++j)
                    if (!a[i][j]) make(i,j);
                    else a[i][j]=a[j][i]=0;
            sum=top=cnt=Time=0;
            memset(OK,0,sizeof(OK));
            memset(dfn,0,sizeof(dfn));
            memset(low,0,sizeof(low));
            memset(bel,0,sizeof(bel));
            for (i=1;i<=n;++i)
                if (!dfn[i]) Tarjan(i);
            for (i=1;i<=n;++i) sum+=OK[i];
            printf("%d
    ",n-sum);
            n=gi(),m=gi();
        }
        return 0;
    }
    
    

    The End

  • 相关阅读:
    记录一个Heisenbug!
    MATLAB(一):矩阵基本操作
    MATLAB基础(三):MATLAB基本运算与字符串处理
    MATLAB基础(二):变量与矩阵
    MATLAB基础(一):简介及数值数据特点与常用数学函数
    用位运算实现四则运算
    指针:C语言二级指针与二维数组
    单片机基础(八):单片机串行口结构与工作方式及应用
    单片机基础(七):串行通信概念及其工作原理
    单片机基础(六):单片机定时/控制器的控制接口
  • 原文地址:https://www.cnblogs.com/Bhllx/p/10617712.html
Copyright © 2020-2023  润新知