题意:有n个骑士经常举行圆桌会议,商讨大事,每次圆桌会议至少应有3个骑士参加,且互相憎恨的骑士不能坐在圆桌旁的相邻位置,如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数,以防赞同和反对票一样多,知道哪些骑士互相憎恨之后,你的任务是统计有多少个骑士不可能参加任何一个会议。
分析:求出原图的补图后,问题转化为判断一个点是否存在一个奇数环内,一个环内的所有点一定在同一个点双连通分量内,我们求出所有的点双连通分量后,判断一下它是否为一个二分图,若不是二分图则连通分量内的所有点均至少存在一个奇环内。注意对割点染色时的特殊判断。
#include <cstdio>
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <utility>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MOD 1000000007
using namespace std;
int n,m,ans,bcc_cnt,dfs_clock,pre[1005],bccno[1005],low[1005],color[1005];
bool hate[1005][1005],isans[1005];
struct Edge
{
int u,v;
Edge(int x,int y)
{
u = x;
v = y;
}
};
stack <Edge> S;
vector <int> bcc[1005];
int dfs(int u,int fa)
{
low[u] = pre[u] = ++dfs_clock;
for(int v = 1;v <= n;v++)
if(!hate[u][v])
{
Edge e = Edge(u,v);
if(!pre[v])
{
S.push(e);
low[u] = min(low[u],dfs(v,u));
if(low[v] >= pre[u])
{
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);
low[u] = min(low[u],pre[v]);
}
}
return low[u];
}
bool jud(int u,int colm,int edg)
{
bool flag = true;
color[u] = colm;
for(int v = 1;v <= n;v++)
if(!hate[u][v] && bccno[v] == edg)
if(!color[v]) flag = flag && jud(v,3-colm,edg);
else
if(color[v] != 3-colm) return false;
return flag;
}
int main()
{
while(scanf("%d%d",&n,&m) == 2)
{
if(n == 0 && m == 0) break;
memset(hate,0,sizeof(hate));
memset(pre,0,sizeof(pre));
memset(bccno,0,sizeof(bccno));
memset(isans,0,sizeof(isans));
bcc_cnt = ans = 0;
for(int i = 1;i <= n;i++) hate[i][i] = true;
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
hate[x][y] = hate[y][x] = true;
}
for(int i = 1;i <= n;i++)
{
dfs_clock = 0;
if(!pre[i]) dfs(i,-1);
}
for(int i = 1;i <= bcc_cnt;i++)
{
memset(color,0,sizeof(color));
if(bcc[i].size() <= 2) continue;
for(int u : bcc[i]) bccno[u] = i;
bool flag = !jud(bcc[i][0],1,i);
for(int u : bcc[i]) isans[u] = isans[u] || flag;
}
for(int i = 1;i <= n;i++)
if(isans[i]) ans++;
printf("%d\n",n-ans);
}
}