hdu 1814 Peaceful Commission 题解

题目传送门

题目大意: n n n 个团队,每个团队两个人,现在要组成一个 n n n 人的组织,要求每个团队中只能有 1 1 1 个人在组织里,给出 m m m 组憎恶关系,相互憎恶的两人不能同时在组织里,给出一种组成组织的方案。

题解

2 − S A T 2-SAT 2SAT 裸题,同一个团队的两人其实分别代表 0 / 1 0/1 0/1,根据憎恶关系造出图后,从编号小的团队开始跑,先跑团队中的 0 0 0,把能跑到的点都加入组织,假如和之前的方案有冲突,就尝试跑 1 1 1,如果依然有冲突,那么无解。

由于之前做的决策不会影响到答案的可行性,所以每次只考虑调整自己而不需要考虑前面的决策。具体来说就是不存在这类情况:前面团队 i i i 选了 0 0 0,枚举到 j j j 的时候发现不管选 0 0 0 还是 1 1 1 都和 i i i 有冲突,即从 j 0 j_0 j0 j 1 j_1 j1 出发都会走到 i 1 i_1 i1

看起来好像是之前的决策出了问题,即团队 i i i 不应该选 0 0 0 而应该选 1 1 1,但事实上,考虑 2 − S A T 2-SAT 2SAT 的建边规则,然后手玩一下就会发现,如果 j 0 j_0 j0 j 1 j_1 j1 都能走到 i 1 i_1 i1,那么 i 0 i_0 i0 就能同时走到 j 0 j_0 j0 j 1 j_1 j1,在这种情况下,团队 i i i 不可能选 0 0 0

于是代码如下:

#include <cstdio>
#include <cstring>
#define maxn 20010

int n,m;
struct edge{int y,next;};
edge e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
int kk(int x){return x%2==1?x+1:x-1;}
bool v[maxn];
int zhan[maxn],t;
bool dfs(int x)
{
	if(v[x])return true;
	if(v[kk(x)])return false;
	v[x]=true;zhan[++t]=x;
	for(int i=first[x];i;i=e[i].next)
	if(!dfs(e[i].y))return false;
	return true;
}
bool two_SAT()
{
	for(int i=1;i<=2*n;i++)
	{
		if(v[i]||v[kk(i)])continue;
		t=0;
		if(!dfs(i))
		{
			while(t)v[zhan[t--]]=false;
			if(!dfs(kk(i)))return false;
		}
	}
	return true;
}

int main()
{
	while(~scanf("%d",&n))
	{
		scanf("%d",&m);
		memset(first,0,sizeof(first));len=0;
		for(int i=1,x,y;i<=m;i++)scanf("%d %d",&x,&y),
		buildroad(x,kk(y)),buildroad(y,kk(x));
		memset(v,false,sizeof(v));
		if(two_SAT())
		{
			for(int i=1;i<=2*n;i++)
			if(v[i])printf("%d\n",i);
		}
		else printf("NIE\n");
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值