POJ2942

来源:互联网 发布:大数据新能源建设 编辑:程序博客网 时间:2024/05/16 15:37

Problem : Knights of the Round Table
Description :

有N个要围着圆桌武士开会,敌对关系的武士不能坐在一起。而且,一个桌子上的武士人数必须是奇数。现在问你最少要开除多少武士才能开会。

Solution :

点双连通分量+二分图奇圈判定+标记。这个题目我参考了这位大牛的博客和刘汝佳的书。
首先我们要建立补图,把能坐在一起的武士连边。然后求一个点双连通分量,因为点双连通分量内部点总有两条节点不重复的路径,其实就是类似环。这也符合了圆桌的背景,左边一个人,右边一个人。
其次就是要判定奇圈了,假设点双连通分量中含有奇圈,但是整个分量中的点数是偶数,那么这几个人是不是可以在一起开会呢?答案是可以的,看下图:
这里写图片描述
整个图示一个点连通分量,点v不在奇圈中,但是根据点双连通图的性质,v一定可以到达u1u2,而且这两条路径不重复。那么u1>u2的两条路径必然有一条是奇数有一条是偶数,因为u1, u2是在同一个奇圈中的,那么必然可以构造一个新的奇圈包括v,看下图就理解了。

由于我是第一次写二分图的染色判定,因此直接按照上面大牛的写法来写了,但是发现不对,因为染色判定如果发现同色那么就立即返回,一个点扩展的所有结点都不同色才能返回true。下面我贴出来了这两种写法。

这里写图片描述

这个题做了一天,启示也是挺深的。

Code(C++) :

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stack>#define MAX(a,b) ((a)>(b)? (a):(b))#define MIN(a,b) ((a)<(b)? (a):(b))typedef struct tagEdge{    int from,to;    tagEdge(){}    tagEdge(int from,int to):from(from),to(to){}    bool operator==(const tagEdge &o)const{        return from==o.from&&to==o.to;    }}Edge;using namespace std;const int M=1000+5;int dfn[M],low[M];bool map[M][M],G[M][M];bool is_same_bcc[M];int color[M];int bcc[2*M],num;bool ans[M];int n,m;int num_dfn;stack<Edge> sta;bool bicoloring(int x,int c){    color[x]=c;    for(int i=1;i<=n;i++)        if(map[x][i]&&is_same_bcc[i]){            if(!color[i]){                if(!bicoloring(i,3-c))                    return false;            }            else if(color[i]==color[x])                return false;        }    return true;}void dfs(int from,int fa){    dfn[from]=low[from]=++num_dfn;    for(int to=1;to<=n;to++)        if(map[from][to]){            if(to!=fa&&dfn[to]<dfn[from]){                if(!dfn[to]){                    Edge EE=Edge(from,to);                    sta.push(EE);                    dfs(to,from);                    low[from]=MIN(low[from],low[to]);                    if(dfn[from]<=low[to]){                        num=0;                        memset(is_same_bcc,false,sizeof(is_same_bcc));                        memset(color,0,sizeof(color));                        for(Edge tmp=sta.top();;tmp=sta.top()){                            sta.pop();                            bcc[num++]=tmp.from;                            bcc[num++]=tmp.to;                            is_same_bcc[tmp.from]=true;                            is_same_bcc[tmp.to]=true;                            if(tmp==EE||sta.empty())                                break;                        }                        if(!bicoloring(bcc[0],1)){                            for(int i=0;i<num;i++)                                ans[bcc[i]]=true;                        }                    }                }else                    low[from]=MIN(low[from],dfn[to]);            }        }}int main(){    //freopen("in.data","r",stdin);    while(scanf("%d%d",&n,&m),n+m){        memset(G,false,sizeof(G));        memset(dfn,0,sizeof(dfn));        memset(low,0,sizeof(low));        memset(ans,false,sizeof(ans));        for(int i=1;i<=n;i++)            G[i][i]=true;        int x,y;        for(int i=1;i<=m;i++){            scanf("%d%d",&x,&y);            G[x][y]=G[y][x]=true;        }        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                map[i][j]=(G[i][j]==false);        num_dfn=0;        for(int i=1;i<=n;i++)            if(!dfn[i])                dfs(i,-1);        int sum=0;        for(int i=1;i<=n;i++)            sum+=(int)ans[i];        printf("%d\n",n-sum);    }    return 0;}
0 0
原创粉丝点击