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",n-sum);
        n=gi(),m=gi();
    }
    return 0;
}

The End

posted @ 2019-03-28 21:11  薄荷凉了夏  阅读(293)  评论(0编辑  收藏  举报