Party
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9724 Accepted Submission(s): 3048
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
题目大意 : 有N对夫妻, M对敌对关系, 有敌对关系的人无法出席同一场宴会, 夫妻当中必须有一个人出席, 问你是否可以满足条件,如果可以, 输出 YES, 否则 输出 NO
思路 : 经典的2-SAT问题, 2-SAT是集合中数量为1选其中一个,并附加一些限制条件, 当一个点存在时,一定存在另一个点与之相连(两个点必须选一个, 一个点不能选, 所以必须连一个点),最后判断每个点和他对应的点是否在一个环内, 如果在说明不满足条件
Accepted code
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 2e3 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
vector <int> e[MAXN << 1];
int dfn[MAXN], low[MAXN], n, m, tot;
int suo[MAXN], scnt;
bool vis[MAXN];
stack <int> st;
void init() {
for (int i = 0; i < 2 * n; i++) dfn[i] = low[i] = suo[i] = 0, vis[i] = false, e[i].clear();
tot = scnt = 0;
}
void tarjan(int x, int fa) {
dfn[x] = low[x] = ++tot;
st.push(x); vis[x] = true;
for (int i = 0; i < SZ(e[x]); i++) {
int vi = e[x][i];
if (!dfn[vi]) {
tarjan(vi, x);
Min(low[x], low[vi]);
}
else if (vis[vi]) Min(low[x], dfn[vi]);
}
if (dfn[x] == low[x]) {
scnt++; int k;
do {
k = st.top(); st.pop();
vis[k] = false;
suo[k] = scnt;
} while (k != x);
}
}
int main()
{
while (~sc("%d %d", &n, &m)) {
init();
for (int i = 0; i < m; i++) {
int a1, a2, c1, c2, ui, vi;
sc("%d %d %d %d", &a1, &a2, &c1, &c2);
ui = a1, vi = a2;
if (c1) ui += n; if (c2) vi += n;
if (c2) e[ui].push_back(vi - n);
else e[ui].push_back(vi + n);
if (c1) e[vi].push_back(ui - n);
else e[vi].push_back(ui + n);
}
for (int i = 0; i < 2 * n; i++) { // 缩点判环
if (!dfn[i]) tarjan(i, i);
}
bool flag = true;
for (int i = 0; i < n; i++) {
if (suo[i] == suo[i + n]) { // 对应的点在一个集合
flag = false;
break;
}
}
if (flag) printf("YES\n");
else printf("NO\n");
}
return 0;
}