UVALIVE 3523 双连通分量+二分图染色

来源:互联网 发布:捷联惯导速度算法 编辑:程序博客网 时间:2024/06/05 05:37

题目链接:https://vjudge.net/problem/18122

题意:

有n个骑士经常举行圆桌会议,每次圆桌会议至少要有3个骑士参加(且每次参加的骑士数量是奇数个),且所有

互相憎恨的骑士不能坐在圆桌旁的相邻位置,问有多少个骑士不可能参加任何一个会议

解法:

这题最终转化为求解图中结点是在一个奇圈上。首先我们可以把所有的圈找出来,即找到所有的双连通分量,

跑一边tarjan算法即可。之后重头戏来了,我们获得一个双连通块之后,怎么判断块中的点是不是在一个奇圈

上?答案——二分图染色!

定理:一个图为二分图的充分必要条件是图中不存在奇圈。

因此,如果一个双连通块为二分图,则不存在奇圈;如果一个双连通块不是二分图,则一定存在奇圈。但是这

样还有一个问题,我们能否保证所有非二分图双连通块的结点都在一个奇圈上?答案也是可以的。

可以这么想,因为块中一定存在一个奇圈,又因为块双连通,即任意结点u到结点v必存在两条点不重复路径,

那么假设v在奇圈上,我们考虑u到v的两条路径:若u也在一个奇圈上,则u在一个奇圈上的条件满足;若u在

一个偶圈上,则u到v必然存在一奇一偶两条路径,则可以形成一个新的奇圈。因此,双连通块中的结点u必然

在一个奇圈上。

///UVALIVE 5135#include <bits/stdc++.h>using namespace std;const int maxn = 2010;const int maxm = 1000010;struct Edge{    int u, v;    Edge(int u=0, int v=0):u(u),v(v){}}e[maxm];int n,m,stamp,dfn[maxn],low[maxn],iscut[maxn],bccno[maxn];int scnt,stk[maxm],bcc_cnt;vector<int>vec[maxn],bcc[maxn];void tarjan(int index, int fa){    int child=0,tmp;    dfn[index]=low[index]=++stamp;    for(int i=0; i<vec[index].size(); i++){        tmp=e[vec[index][i]].v;        if(!dfn[tmp]){            stk[++scnt]=vec[index][i], child++;            tarjan(tmp,index);            low[index]=min(low[index],low[tmp]);            if(low[tmp]>=dfn[index]){                iscut[index]=1;                bcc[++bcc_cnt].clear();                while(1){                    int num=stk[scnt--];                    if(bccno[e[num].u]!=bcc_cnt){                        bcc[bcc_cnt].push_back(e[num].u);                        bccno[e[num].u]=bcc_cnt;                    }                    if(bccno[e[num].v]!=bcc_cnt){                        bcc[bcc_cnt].push_back(e[num].v);                        bccno[e[num].v]=bcc_cnt;                    }                    if(e[num].u==index&&e[num].v==tmp)                        break;                }            }        }        else if(dfn[tmp]<dfn[index]&&tmp!=fa){            stk[++scnt]=vec[index][i];            low[index]=min(low[index],dfn[tmp]);        }    }    if(fa<0&&child==1){        iscut[index]=0;    }}void find_bcc(){    memset(dfn, 0, sizeof(dfn));    memset(low, 0, sizeof(low));    memset(iscut, 0, sizeof(iscut));    memset(bccno, 0, sizeof(bccno));    memset(bcc, 0, sizeof(bcc));    stamp=scnt=bcc_cnt=0;    for(int i=1; i<=n; i++){        if(!dfn[i]){            tarjan(i,-1);        }    }}int odd[maxn], color[maxn], b;bool dfs(int index,int c){    if(bccno[index]!=b)        return 1;    color[index]=c;    for(int i=0;i<vec[index].size();i++)    {        int tmp=e[vec[index][i]].v;        if(color[index]==color[tmp])            return 0;        if(!color[tmp]&&!dfs(tmp,3-c))            return 0;    }    return 1;}int A[maxn][maxn];int main(){    while(scanf("%d%d", &n,&m)!=EOF&&n+m){        for(int i=1; i<=n; i++) vec[i].clear();        memset(A, 0, sizeof(A));        for(int i=0; i<m; i++){            int u,v;            scanf("%d%d", &u,&v);            A[u][v]=A[v][u]=1;        }        int len=0;        for(int i=1; i<=n; i++){            for(int j=i+1; j<=n; j++){                if(!A[i][j]){                    e[len]=Edge(i,j);                    vec[i].push_back(len++);                    e[len]=Edge(j,i);                    vec[j].push_back(len++);                }            }        }        find_bcc();        memset(odd, 0, sizeof(odd));        for(int i=1; i<=bcc_cnt; i++){            memset(color, 0, sizeof(color));            b=i;            for(int j=0;j<bcc[i].size();j++)                bccno[bcc[i][j]]=i;            if(!dfs(bcc[i][0], 1))                for(int j=0;j<bcc[i].size();j++)                    odd[bcc[i][j]]=1;        }        int ans=0;        for(int i=1; i<=n; i++){            if(!odd[i]){                ans++;            }        }        printf("%d\n", ans);    }    return 0;}
0 0
原创粉丝点击