题目链接: https://cn.vjudge.net/problem/UVA-1364
题目大意:有n个骑士经常举行圆桌会议,商讨大事。每次圆桌会议至少应有3个骑士参加,且相互憎恨得骑士不能坐在圆桌旁得相邻位置。如果发生分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数,以防止赞同和反对票一样多。知道哪些骑士相互憎恶之后,你的任务是统计有多少个骑士不可能参加任何一个会议。
分析:简单圈上的所有节点必然属于同一个双连通分量,因此需要先找出所有双连通分量。二分图是没有奇圈的,因此我们只需要关注那些不是二分图的双连通分量。(参考于刘汝佳《训练指南》P317页)
代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <math.h>
#include <stack>
using namespace std;
const int maxn =1000+5;
int n,m;
int pre[maxn],bccno[maxn],dfs_clock,bcc_cnt,odd[maxn],color[maxn];
int A[maxn][maxn];
vector<int>G[maxn],bcc[maxn];
struct Edge
{
int u,v;
Edge(int u,int v):u(u),v(v) {};
};
stack<Edge> S;
void init()
{
dfs_clock=bcc_cnt=0;
memset(pre,0,sizeof(pre));
memset(bccno,0,sizeof(bccno));
memset(A,0,sizeof(A));
memset(odd,0,sizeof(odd));
for(int i=0; i<n; i++)
G[i].clear();
}
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 dfs(int u,int fa)
{
int lowu = pre[u] = ++dfs_clock;
for(int i=0; i<G[u].size(); i++)
{
int v=G[u][i];
Edge e=(Edge){u,v};
if(!pre[v])
{
S.push(e);
int lowv = dfs(v,u);
lowu =min(lowu,lowv);
if(lowv>=pre[u])
{
bcc_cnt++;
bcc[bcc_cnt].clear();
for(;;)
{
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(e);
lowu=min(lowu,pre[v]);
}
}
return lowu;
}
int main()
{
while(scanf("%d %d",&n,&m)&&(n+m))
{
init();
for(int i=0; i<m; i++)
{
int u,v;
scanf("%d %d",&u,&v);
u--;
v--;
A[u][v]=A[v][u]=1;
}
for(int u=0; u<n; u++)
for(int v=u+1; v<n; v++)
if(!A[u][v])
{
G[u].push_back(v),G[v].push_back(u);
}
for(int i=0; i<n; i++)
{
if(!pre[i])
dfs(i,-1);
}
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\n",ans);
}
return 0;
}