[2-sat][POI2001]和平委员会

样例输入
3 2
1 3
2 4
样例输出
1
4
5

分析:
2-sat模板题,两个人仇视的话就分别把其中一人和另一人所在的另一人连边,每个条件要连两条边,然后tarjan求强连通分量构造合法解即可,不会2-sat的童鞋可以自行学习,包括2-sat问题的判定和构造合法解的方案

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=400005,M=200005;
int sta[N],insta[N],top=0,tot=0,head[M],nxt[M],vis[M],dfn[N],low[N],sign=0,scc=0,id[N];
inline void add(int x,int y){vis[++tot]=y,nxt[tot]=head[x];head[x]=tot;}
void tarjan(int v){
	low[v]=dfn[v]=++sign;
	sta[++top]=v,insta[v]=1;
	for(int i=head[v];i;i=nxt[i]){
		int y=vis[i];
		if(!dfn[y]) {tarjan(y);low[v]=min(low[y],low[v]);}
		else if(insta[y]) low[v]=min(low[v],dfn[y]);
	}
	if(low[v]==dfn[v]){
		++scc;int i=sta[top];
		while(i!=v){id[i]=scc;insta[i]=0,i=sta[--top];}
		top--;insta[v]=0,id[v]=scc;
	}
	return;
}
int opp[N],val[N];
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int a,b;scanf("%d%d",&a,&b);
		add(a,(b%2==0?b-1:b+1));
		add(b,(a%2==0?a-1:a+1));
	}
	for(int i=1;i<=n*2;i++) if(!dfn[i]) tarjan(i);
	for(int i=1;i<=n*2;i+=2){
		if(id[i]==id[i+1]) {puts("NIE");return 0;}
		opp[i]=i+1,opp[i+1]=i;
	}
	for(int i=1;i<=2*n;i++) val[i]=id[i]>id[opp[i]];
	for(int i=1;i<=2*n;i++) if(!val[i]) cout<<i<<'\n';
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值