2-SAT - 2019.10.7 聚会
作者:互联网
题面
【问题描述】
有 \(n\) 对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有 \(1\) 人可以列席。在 \(2n\) 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的 \(2\) 个人是不会同时出现在聚会上的。有没有可能会有 \(n\) 个人同时列席?
【输入格式】
包含多组数据,对于每一组数据:
第一行一个正整数 \(n\),表示有 \(n\) 对夫妻被邀请 (\(n\le 1000\))
第二行一个正整数 \(m\),表示有 \(m\) 对矛盾关系 ( \(m < (n - 1)^2\))
在接下来的 \(m\) 行中,每行会有 \(4\) 个数字,分别是 \(A_1,A_2,C_1,C_2\)
\(A_1,A_2\) 分别表示是夫妻的编号, \(C_1,C_2\) 表示是妻子还是丈夫 ,\(0\) 表示妻子 ,\(1\) 是丈夫
夫妻编号从 \(0\) 到 \(n -1\)
【输出格式】
如果存在一种可以 \(n\) 个人同时列席的情况,则输出 YES
,否则输出 NO
【输入样例】
2
1
0 1 1 1
【输出样例】
YES
【数据范围】
每个数据不超过10组。
解
实际上,此题的描述是不完全的,但是在(多次)估摸提议后仍然通过了此题。这题是一道简单的 2-SAT 问题。设 \(P_i\) 表示第 \(i\) 对夫妻中丈夫去,否则妻子去,可以建图。
程序
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
#define MAXN 1020
int n, m;
vector<int> g[2 * MAXN];
int dfn[2 * MAXN], color[2 * MAXN], low[2 * MAXN], s[2 * MAXN], sp, cnt, col;
void tarjan(int u) {
dfn[u] = low[u] = ++cnt;
// s.push(u);
s[++sp] = u;
for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it++) {
if (!dfn[*it]) {
tarjan(*it);
low[u] = min(low[u], low[*it]);
} else if (!color[*it]) {
low[u] = min(low[u], low[*it]);
}
}
if (low[u] == dfn[u]) {
color[u] = ++col;
while (s[sp] != u) {
color[s[sp]] = color[u];
sp--;
}
sp--;
}
}
void solve() {
memset(dfn, 0, sizeof(dfn));
memset(color, 0, sizeof(color));
memset(low, 0, sizeof(low));
memset(s, 0, sizeof(s));
cnt = col = sp = 0;
cin >> m;
for (int i = 0; i < 2 * n; i++)
g[i].clear();
for (int i = 0; i < m; i++) {
int a1, a2, c1, c2;
cin >> a1 >> a2 >> c1 >> c2;
// cout << " " << a1 + c1 * n << " " << a2 + c2 * n << endl;
g[a1 + c1 * n].push_back(a2 + (1 - c2) * n);
g[a2 + c2 * n].push_back(a1 + (1 - c1) * n);
}
for (int i = 0; i < 2 * n; i++)
if (!dfn[i]) tarjan(i);
for (int i = 0; i < n; i++)
if (color[i] == color[i + n]) {
cout << "NO" << endl;
return;
}
cout << "YES" << endl;
}
int main() {
while (cin >> n) {
solve();
}
return 0;
}
标签:2019.10,color,sp,++,int,dfn,low,聚会,SAT 来源: https://www.cnblogs.com/lrw04/p/11815947.html