题目大意:有n个骑士要在圆桌上开会,但是相互憎恶的两个骑士不能相邻,现在已知骑士们之间的憎恶关系,问有几个骑士一定不能参加会议。参会骑士至少有3个且有奇数个。
题目分析:在可以相邻的骑士之间连一条无向边,构成一张图G。则问题变成了有几个节点不在奇圈(有奇数个节点的圈)内,并且一个点在圈内最多出现一次。如果G不连通,应该对每一个分量分别求解。奇圈上的点一定在同一个双连通分量内,要找出所有的双连通分量。但是能构成二分图的双连通分量中一定没有奇圈,不能构成二分图的双连通分量中一定含有奇圈,并且分量中所有的点都在奇圈上,所有还要判断每一个双连通分量能不能构成二分图。
其实就是一道模板题。。。
代码如下:
# include<iostream> # include<cstdio> # include<vector> # include<stack> # include<cstring> # include<algorithm> using namespace std; const int maxn=1005; struct Edge { int u,v; Edge(int _u,int _v):u(_u),v(_v){} }; stack<Edge>S; vector<int>G[maxn],bcc[maxn]; int bcc_cnt,dfs_cnt,low[maxn],pre[maxn],odd[maxn],color[maxn],bccno[maxn],iscut[maxn],A[maxn][maxn]; int dfs(int u,int fa) { int lowu=pre[u]=++dfs_cnt; int child=0; for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(!pre[v]){ S.push(Edge(u,v)); ++child; int lowv=dfs(v,u); lowu=min(lowu,lowv); if(lowv>=pre[u]){///存在一个满足条件的v,便能说明u是割点。 iscut[u]=1; bcc[++bcc_cnt].clear(); while(1) { Edge x=S.top(); S.pop(); if(bccno[x.u]!=bcc_cnt){ bcc[bcc_cnt].push_back(x.u); bccno[x.u]=bcc_cnt; } if(bccno[x.v]!=bcc_cnt){ bcc[bcc_cnt].push_back(x.v); bccno[x.v]=bcc_cnt; } if(x.u==u&&x.v==v) break; } } } else if(pre[v]<pre[u]&&v!=fa){ S.push(Edge(u,v)); lowu=min(lowu,pre[v]); } } if(fa<0&&child==1)///根节点只有1个子节点时不是割点。 iscut[u]=0; low[u]=lowu; return lowu; } void find_bcc(int n) { memset(pre,0,sizeof(pre)); memset(iscut,0,sizeof(iscut)); memset(bccno,0,sizeof(bccno)); dfs_cnt=bcc_cnt=0; for(int i=0;i<n;++i) if(!pre[i]) dfs(i,-1); } bool bipartite(int u,int b) { for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(bccno[v]!=b) continue; if(color[v]==color[u]) return false; if(!color[v]){ color[v]=3-color[u]; if(!bipartite(v,b)) return false; } } return true; } int main() { int n,m,a,b; while(scanf("%d%d",&n,&m)&&(n+m)) { memset(A,0,sizeof(A)); for(int i=0;i<n;++i) G[i].clear(); while(m--){ scanf("%d%d",&a,&b); --a,--b; A[a][b]=A[b][a]=1; } for(int i=0;i<n;++i) for(int j=i+1;j<n;++j) if(!A[i][j]) G[i].push_back(j),G[j].push_back(i); find_bcc(n); memset(odd,0,sizeof(odd)); for(int i=1;i<=bcc_cnt;++i){ memset(color,0,sizeof(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; } int ans=n; for(int i=0;i<n;++i) if(odd[i]) --ans; printf("%d ",ans); } return 0; }