0
点赞
收藏
分享

微信扫一扫

【 HDU - 3062】Party(2-sat)

题干:

有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

解题报告:

   直接2-sat裸题。因为题干中说一对夫妻有且只有一个人参加聚会,所以符合元素和元素的非 的性质。所以如果说A和B有仇,那就A->b , B -> a这样就好。

AC代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 3000 + 5;
struct Edge {
int v,ne;
} e[5000005];
int n,m;
int head[MAX],tot;//1~n代表妻子,n+1到2*n代表丈夫
void add(int u,int v) {
e[++tot].v = v;e[tot].ne = head[u];head[u] = tot;
}
int DFN[MAX],LOW[MAX],col[MAX],vis[MAX],index,stk[MAX],scc,clk;
void Tarjan(int x) {
DFN[x] = LOW[x] = ++clk;
vis[x] = 1;stk[++index] = x;
for(int i = head[x]; ~i; i = e[i].ne) {
int v = e[i].v;
if(!DFN[v]) {
Tarjan(v);
LOW[x] = min(LOW[x],LOW[v]);
}
else if(vis[v]) LOW[x] = min(LOW[x],DFN[v]);
}
if(LOW[x] == DFN[x]) {
scc++;
while(1) {
int tmp = stk[index--];
col[tmp] = scc;vis[tmp] = 0;
if(tmp == x) break;
}
}
}
void init(int n) {
tot=0;clk=index=scc=0;
for(int i = 1; i<=2*n; i++) head[i] = -1,DFN[i]=LOW[i]=vis[i]=col[i]=0;
}
int main()
{
while(~scanf("%d%d",&n,&m)) {
init(n);
for(int c1,c2,a1,a2,i = 1; i<=m; i++) {
scanf("%d%d%d%d",&a1,&a2,&c1,&c2);a1++,a2++;
int U = a1 + c1*n,u=a1+(1-c1)*n;
int V = a2 + c2*n,v=a2+(1-c2)*n;
add(U,v);add(V,u);
}
for(int i = 1; i<=2*n; i++) {
if(!DFN[i]) Tarjan(i);
}
int flag = 1;
for(int i = 1; i<=n; i++) {
if(col[i] == col[i+n]) {flag = 0;break;}
}
if(flag) puts("YES");
else puts("NO");
}

return 0 ;
}
//20:10-20:39

总结:

当然对于这一题还有另一种建图方式:​​链接​​

对于这道题,我们首先要虚拟节点,对于编号为i的妻子a和丈夫b,做法如下: (我用!来表示非,毕竟那些符号不好办)

对妻子a: 对应的a虚拟为 节点 i ,对应的!a虚拟为节点 i + 2*N, 
对丈夫b: 对应的b虚拟为节点i + N ,!b虚拟为节点 i + N + 2*N。 这样的话我们得到了4*N -1个节点。

由题意有以下建边方案

一:夫妻a,b只能去一人且必须去一人。 得布尔表达式 (!a -> b)合取(!b -> a)合取(b -> !a)合取(a -> !b)

二:有矛盾的两人不能同时去,这就意味着可能都不去。 得布尔表达式 (a -> !b)合取(b -> !a)


举报

相关推荐

0 条评论