有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
题意:有n对夫妻,每对夫妻中只有1人可以列席。在2n 个人中有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?
思路:2-SAT模板题
AC代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<set>
#include<vector>
#include<queue>
#include<iostream>
using namespace std;
const int maxn = 1e6 + 100;
const int inf = 0x3f3f3f3f;
typedef long long ll;
struct node
{
int v, next;
}edge[maxn];
int head[maxn], dfn[maxn], low[maxn], instack[maxn], Stack[maxn], belong[maxn];
int n, tot, index, top, cnt;
void addedge(int u, int v)
{
edge[tot].v = v;
edge[tot].next = head[u];
head[u] = tot++;
return;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++index;
instack[u] = 1;
Stack[top++] = u;
for (int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (low[u] == dfn[u])
{
cnt++;
int v;
do
{
v = Stack[--top];
instack[v] = 0;
belong[v] = cnt;
} while (u != v);
}
}
int main()
{
while (scanf("%d", &n) != EOF)
{
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
tot=index =0;
top = 0;
cnt = 0;
int m;
scanf("%d", &m);
for (int i = 0; i < m; i++)
{
int a1, a2, c1, c2;
scanf("%d%d%d%d", &a1, &a2, &c1, &c2);
//矛盾关系对应的布尔公式为(xVy),转化成两个蕴含式即为有向图中对应的边
int x=a1+(c1 == 0 ? 1:0)*n;//丈夫(c1=0)在0~n-1之间,妻子在n到2*n-1之间
int y=a2+(c2 == 0 ? 1:0)*n;
addedge((x >= n ? x-n:x+n),y);
addedge((y >= n ? y-n:y+n),x);
}
for (int i = 0; i < n << 1; i++)
{
if (!dfn[i])
{
tarjan(i);
}
}
int flag = 0;
for (int i =0;i<n; i++)
{
if (belong[i] == belong[i+n])
{
flag =1;
}
}
if (flag)
{
printf("NO\n");
}
else
{
printf("YES\n");//多久没错大小写了,这次可给我好好上了一课
}
}
return 0;
}
在建边的时候网上普遍的做法是:
a = (a << 1) + c;
b = (b << 1) + d;
addedge(a, b ^ 1);
addedge(b, a ^ 1);
这个*2的地方实在是看不懂,还是课本上的做法好理解