HDOJ 题目3062 Party(2-sat)

本文探讨了如何通过算法解决有矛盾的夫妻参加聚会时只能有一方出席的问题,确保至少有n个人能同时出席。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Party

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4580    Accepted Submission(s): 1508


Problem Description
有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?
 

Input
n: 表示有n对夫妻被邀请 (n<= 1000)
m: 表示有m 对矛盾关系 ( m < (n - 1) * (n -1))

在接下来的m行中,每行会有4个数字,分别是 A1,A2,C1,C2
A1,A2分别表示是夫妻的编号
C1,C2 表示是妻子还是丈夫 ,0表示妻子 ,1是丈夫
夫妻编号从 0 到 n -1
 

Output
如果存在一种情况 则输出YES
否则输出 NO
 

Sample Input
  
2 1 0 1 1 1
 

Sample Output
  
YES
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   3060  3068  3063  3064  3065 
 ac代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a>b?b:a)
int belong[101000],dfn[101000],low[101000],head[101000],ins[101000],stack[101000];
int cnt,taj,time,top;
int n,m;
struct s
{
	int u,v,next;
}edge[1010*2*200];
void init()
{
	cnt=taj=time=0;
	memset(head,-1,sizeof(head));
	memset(low,-1,sizeof(low));
	memset(dfn,-1,sizeof(dfn));
	memset(ins,0,sizeof(ins));
	memset(belong,-1,sizeof(belong));
}
void addedge(int u,int v)
{
	edge[cnt].u=u;
	edge[cnt].v=v;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}
void add(int a,int b,int c,int d)
{
	if(c==0&&d==0)
	{
		addedge(a<<1,(b<<1)+1);
		addedge(b<<1,(a<<1)+1);
	}
	else
		if(c==0&&d==1)
		{
			addedge(a<<1,b<<1);
			addedge((b<<1)+1,(a<<1)+1);
		}
		else
			if(c==1&&d==0)
			{
				addedge((a<<1)+1,(b<<1)+1);
				addedge(b<<1,a<<1);
			}
			else
				if(c==1&&d==1)
				{
					addedge((a<<1)+1,b<<1);
					addedge((b<<1)+1,a<<1);
				}
}
void tarjan(int u)
{
	dfn[u]=low[u]=time++;
	ins[u]=1;
	stack[top++]=u;
	for(int i=head[u];i!=-1;i=edge[i].next)
	{
		int v=edge[i].v;
		if(dfn[v]==-1)
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else
			if(ins[v])
			{
				low[u]=min(dfn[v],low[u]);
			}
	}
	if(dfn[u]==low[u])
	{
		taj++;
		int now;
		do
		{
			now=stack[--top];
			belong[now]=taj;
			ins[now]=0;
		}while(now!=u);
	}
}
int _2sat()
{
	int i;
	for(i=0;i<2*n;i++)
	{
		if(dfn[i]==-1)
			tarjan(i);
	}
	for(i=0;i<n;i++)
	{
		if(belong[2*i]==belong[(2*i)+1])
			return 0;
	}
	return 1;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		int i;
		init();
		for(i=0;i<m;i++)
		{
			int a,b,c,d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			add(a,b,c,d);
		}
		if(_2sat())
			printf("YES\n");
		else
			printf("NO\n");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值