Knights of the Round Table

POJ

洛咕---SP

洛咕---UVA

题意:有(n)个骑士经常举行圆桌会议,商讨大事.每次圆桌会议至少有(3)个骑士参加,且相互憎恨的骑士不能坐在圆桌的相邻位置.如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是大于1的奇数,以防止赞同和反对票一样多.知道那些骑士相互憎恨之后,你的任务是统计有多少骑士不可能参加任何一个会议.(n<=1000,m<=10^6).

分析:建原图的"补图":如果两名骑士没有憎恨关系,则在两个节点之间建立一条无向边.跑无向图(Tarjan)求出图中所有的(v-DCC),用二分图染色法判定每个(v-DCC)中是否存在奇环即可.若存在奇环,则该(v-DCC)中的所有骑士都可以参加会议(因为它们必定都在某个奇环中).

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
    int x=0,o=1;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')o=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*o;
}
const int N=1005;
const int M=1000005;
int n,m,ans,w[N][N];
int tot,head[N],nxt[M],to[M];
int tim,top,cnt,root,BJ;
int dfn[N],low[N],st[M],cut[N];
int belong[N],visit[N],bj[N];
vector<int>dcc[N];
inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
inline void tarjan(int x){
	dfn[x]=low[x]=++tim;st[++top]=x;
	if(x==root&&!head[x]){
		dcc[++cnt].push_back(x);
		return;
	}
	int flag=0;
	for(int i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(!dfn[y]){
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x]){
				++flag;
				if(x!=root||flag>1)cut[x]=1;
				++cnt;int z;
				do{
					z=st[top--];
					dcc[cnt].push_back(z);
				}while(z!=y);
				dcc[cnt].push_back(x);
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}
inline void dfs(int x,int color){
	visit[x]=color;
	for(int i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(belong[y]!=belong[x])continue;
		if(!visit[y])dfs(y,3-color);
		else if(visit[y]==color){
			BJ=1;return;
		}
	}
}
int main(){
	while(1){
		n=read();m=read();if(!n&&!m)break;
		tot=0;ans=0;tim=0;top=0;cnt=0;
		for(int i=1;i<=n;++i){
			head[i]=belong[i]=0;
			dfn[i]=low[i]=0;
			cut[i]=bj[i]=st[i]=0;
		}//多组数据初始化,不想用memset...
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)w[i][j]=0;//初始化
		for(int i=1;i<=n;++i)dcc[i].clear();//清空
		for(int i=1;i<=m;++i){
			int a=read(),b=read();
			w[a][b]=w[b][a]=1;//标记憎恨关系
		}
		for(int i=1;i<n;++i)
			for(int j=i+1;j<=n;++j)
				if(!w[i][j])add(i,j),add(j,i);//建立补图
		for(int i=1;i<=n;++i)if(!dfn[i])root=i,tarjan(i);//tarjan求v-dcc
		for(int i=1;i<=cnt;++i){
			for(int j=0;j<dcc[i].size();++j)
				belong[dcc[i][j]]=i,visit[dcc[i][j]]=0;//初始化
			BJ=0;dfs(dcc[i][0],1);//二分图染色法判定是否存在奇环
			if(BJ){//如果存在,标记这个v-dcc内的点不用被踢出去
				for(int j=0;j<dcc[i].size();++j)bj[dcc[i][j]]=1;
			}
		}
		for(int i=1;i<=n;++i)if(!bj[i])++ans;
		printf("%d
",ans);
	}
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/11590594.html