【poj2942】圆桌骑士Knights of the Round Table【双连通分量】【二分图】【奇圈】

来源:互联网 发布:袁隆平 诺贝尔奖 知乎 编辑:程序博客网 时间:2024/04/30 02:57

传送门:http://poj.org/problem?id=2942

尽管我承认这题我几乎是对着书抄的代码(因为我还不熟- -),但是我还是WA了三次- -数组又没清零。

基本思想就是:

首先把不互相憎恨的骑士连边。

求双连通分量bcc。

判断每个bcc是不是二分图,是的话这个二分图里的骑士都没法参加会议。因为形不成奇圈。

奇圈就是奇数个点连成的圈啦~

二分图是不可能有奇圈的(有的话你告诉我三个点的奇圈中一个点在左边的点集,一个点在右边的点集,那剩下的那个在哪里?)

每个非二分图的双连通分量里的点都可以是某个奇圈的一部分。

为啥?

假设我们有个叫B的非二分图的dcc。

里面至少有一个奇圈C。

我们还假设里面有个点叫v。

根据连通性,从v一定可以到达C中的某个点u1;

根据双连通性,C中还有另外一个u2,使得从v到u1的一条路径和v到u2的一条路径不相交(除起点外无公共结点)。

因为在C中u1到u2的路径长度一奇一偶,所以不管从u2经过v到达u1的路径长度的奇偶性如何,总能构造出一个奇圈使得v属于这个奇圈。

于是这道题就可做了。

注意一个地方:割顶有可能属于多个双连通分量,所以要开个bool数组记录一下。

#include<cstdio>#include<iostream>#include<cstring>#include<stack>#include<vector>#define CLR(x) memset(x,0,sizeof(x))using namespace std;const int maxn=1000+5;const int maxm=2*maxn*maxn;typedef int arr[maxn];struct edge{int u,v;};arr list,color,bccno,pre,low;bool iscut[maxn]={false},odd[maxn];int next[maxm],toit[maxm];int n,m,tot,k1,k2,dfsClock,bccCnt;stack<edge> S;vector<int> bcc[maxn];bool bipartite(int u,int b){for(int k=list[u];k;k=next[k]){if(bccno[toit[k]]!=b) continue;if(color[toit[k]]==color[u]) return false;if(!color[toit[k]]){color[toit[k]]=3-color[u];if(!bipartite(toit[k],b)) return false;}}return true;}int dfs(int u,int f){int lowu=pre[u]=++dfsClock;int child=0,v;for(int k=list[u];k;k=next[k]){v=toit[k];edge e=(edge){u,v};if(!pre[v]){S.push(e);++child;int lowv=dfs(v,u);lowu=min(lowv,lowu);if(lowv>=pre[u]){iscut[u]=true;//u是割顶bccCnt++;bcc[bccCnt].clear();while(1){edge x=S.top();S.pop();if(bccno[x.u]!=bccCnt) bcc[bccCnt].push_back(x.u),bccno[x.u]=bccCnt;if(bccno[x.v]!=bccCnt) bcc[bccCnt].push_back(x.v),bccno[x.v]=bccCnt;if(x.u==u&&x.v==v) break;}}}else if(pre[v]<pre[u]&&v!=f){S.push(e);lowu=min(pre[v],lowu);}}if(f<0&&child==1) iscut[u]=false;return low[u]=lowu;}int find_bcc(int n){int ans=n;for(int i=1;i<=n;++i)if(!pre[i]) dfs(i,-1);for(int i=1;i<=bccCnt;++i){CLR(color);for(int j=0;j<bcc[i].size();++j)bccno[bcc[i][j]]=i;int u=bcc[i][0];color[u]=1;if(!bipartite(u,i))//不是二分图for(int j=0;j<bcc[i].size();++j)odd[bcc[i][j]]=1;//可以构成奇圈}for(int i=1;i<=n;++i) if(odd[i]) ans--;//统计答案return ans;}void add(int a,int b){tot++;next[tot]=list[a];list[a]=tot;toit[tot]=b;}int a[maxn][maxn];inline int read(){int x=0;char ch=getchar();while(!isdigit(ch)&&ch!=-1) ch=getchar();while(isdigit(ch)) x=x*10+ch-48,ch=getchar();return x;}inline void init(){CLR(list);CLR(next);CLR(toit);CLR(color);CLR(odd);CLR(pre);CLR(iscut);CLR(bccno);dfsClock=bccCnt=tot=0;CLR(a);}int main(){int n,m;while((n=read())&&(m=read())){init();for(int i=1;i<=m;++i){k1=read(),k2=read();a[k1][k2]=a[k2][k1]=true;}for(int i=1;i<n;++i)for(int j=i+1;j<=n;++j)if(!a[i][j])add(i,j),add(j,i);printf("%d\n",find_bcc(n));}}


0 0
原创粉丝点击