版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目
题目大意
有 个骑士,给出 对仇恨关系,若 与 有仇恨,他们就不能在圆桌会议上坐相邻的位置。请你求出有多少个骑士无法参加任何一个圆桌会议(例如但不仅限于,某个骑士与其他所有骑士有仇恨关系,他就不能参加任何一个圆桌会议)。要求每个圆桌会议必须由奇数个人参加。
分析
考虑原图的补图,即每个骑士可以和哪些骑士相邻。
一个圆桌会议显然对应的是图上的一个奇环(由奇数个点组成的环),所以我们要求的就是有哪些点不在任何一个奇环上。
下面证明两个引理。
引理一:如果两个点在不同的点双连通分量里面,它们就不可能在一个环里。
证明:点双连通分量是最大的不含割点的连通分量,如果两个点在一个环里,就可以把环
下图中的
,
及割点一起合并起来,这样就形成了一个更大的点双连通分量,与条件矛盾。
引理二:一个点双连通分量只要有一个奇环,那么这里面的所有点都属于某个奇环。
证明:找到这个点双中的奇环,考虑某个不在这个奇环上的点,那它一定是这样连在这个奇环上的:
而不可能是这些情况(否则红点就成了割点):
(上图没有列举完其他情况,但是可以发现其他情况都是不可能的)
那么讨论一下链 的长度:
扫描二维码关注公众号,回复:
7580058 查看本文章
- 若为奇数:那么环 是奇环;
- 若为偶数:那么链 的长度是偶数,则环 是奇环。
得证。
有了这两个引理,我们只需要找所有点双,然后看里面有没有奇环即可。
找奇环的方法:搜索,黑白染色。
代码
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 1000
int N,M;
int Out[MAXN+5];
int Belong[MAXN+5];
bool T[MAXN+5][MAXN+5];
vector<int> G[MAXN+5];
int Color[MAXN+5];
int bfs(int S,int id){
queue<int> Q;
Q.push(S),Color[S]=1;
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int i=0;i<int(G[u].size());i++){
int v=G[u][i];
if(Belong[v]!=id)
continue;
if(!Color[v]){
Color[v]=-Color[u];
Q.push(v);
}
else if(Color[v]==Color[u])
return 1;
}
}
return 0;
}
int cnt;
stack<int> Node;
int dfn[MAXN+5],Low[MAXN+5];
void dfs(int u,int fa){
Node.push(u);
Low[u]=dfn[u]=++cnt;
for(int i=0;i<int(G[u].size());i++){
int v=G[u][i];
if(!dfn[v]){
dfs(v,u);
Low[u]=min(Low[u],Low[v]);
if(Low[v]>=dfn[u]){
vector<int> tmp;
do{
tmp.push_back(Node.top()),Node.pop();
}while(tmp.back()!=v);
tmp.push_back(u);//注意找点双时不要把u点pop掉了
for(int j=0;j<int(tmp.size());j++)
Belong[tmp[j]]=tmp[0];
if(bfs(tmp[0],tmp[0]))
for(int j=0;j<int(tmp.size());j++)
Out[tmp[j]]=0;
for(int j=0;j<int(tmp.size());j++)
Color[tmp[j]]=Belong[tmp[j]]=0;//要清零,因为一个点可以属于多个点双
}
}
else if(v!=fa)
Low[u]=min(Low[u],dfn[v]);
}
}
int main(){
while(scanf("%d%d",&N,&M),N&&M){
memset(T,0,sizeof T);
for(int i=1;i<=M;i++){
int u,v;
scanf("%d%d",&u,&v);
T[u][v]=T[v][u]=1;
}
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++)
if(!T[i][j])
G[i].push_back(j),
G[j].push_back(i);
cnt=0;
while(!Node.empty())
Node.pop();
memset(dfn,0,sizeof dfn);
memset(Low,0,sizeof Low);
memset(Color,0,sizeof Color);
memset(Belong,0,sizeof Belong);
for(int i=1;i<=N;i++)
Out[i]=1;
for(int i=1;i<=N;i++)
if(!dfn[i])
dfs(i,-1);
int Ans=0;
for(int i=1;i<=N;i++)
Ans+=Out[i];
printf("%d\n",Ans);
for(int i=1;i<=N;i++)
G[i].clear();
}
return 0;
}