[POI2001]和平委员会

通过从状态x向状态y连一条有向边表示若状态x存在,那么状态y必须存在。(即2-SAT算法)
建边如下图:

[POI2001]和平委员会_第1张图片
[POI2001]和平委员会_第2张图片

#include 
using namespace std;
const int N=8e3+5,M=2e4+5;
int n,m,x,y;
int now,top,col,dfn[N<<1],low[N<<1],sta[N<<1],color[N<<1],fr[N<<1];
int cnt,head[N<<1];
struct edge{
     int next,to;}e[M<<1];

inline void add(int u,int v)
{
     
	cnt++;
	e[cnt].next=head[u];
	e[cnt].to=v;
	head[u]=cnt;
}

void tarjan(int u)
{
     
	dfn[u]=low[u]=++now;
	sta[++top]=u;
	for (register int i=head[u]; i; i=e[i].next)
	{
     
		if (!dfn[e[i].to])
		{
     
			tarjan(e[i].to);
			low[u]=min(low[u],low[e[i].to]);
		}
		else if (!color[e[i].to]) low[u]=min(low[u],low[e[i].to]);
	}
	if (dfn[u]==low[u])
	{
     
		col++;
		while (sta[top]!=u) color[sta[top]]=col,top--;
		color[sta[top]]=col,top--;
	}
}

int main(){
     
	scanf("%d%d",&n,&m);
	for (register int i=1; i<2*n; i+=2) fr[i]=i+1,fr[i+1]=i;
	for (register int i=1; i<=m; ++i)
	{
     
		scanf("%d%d",&x,&y);
		if (fr[x]==y) continue;
		add(x,fr[y]);  //如果选了x,就要选 和y同一党派的另一人 
		add(y,fr[x]);  //如果选了y,就要选 和x同一党派的另一人 
	}
	for (register int i=1; i<=2*n; ++i) if (!dfn[i]) tarjan(i);
	bool jay=true;
	for (register int i=1; i<2*n; i+=2)
	if (color[i]==color[i+1]) {
     jay=false; break;}
	if (!jay) 
	{
     
		puts("NIE");
		return 0;
	}
	for (register int i=1; i<2*n; i+=2)
	{
     
		if (color[i]<color[i+1]) printf("%d\n",i);
		//如果选了i+1,就一定要选i,既然不能都选,那么就只能选i 
		else printf("%d\n",i+1);		
	}
return 0;
}

你可能感兴趣的:(2-SAT,强连通分量)