hdu3062Party(2-SAT入门)
题目描述:
有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?
思路:2-sat模板题,夫妻不能同时出席宴会,而题目问是否能所有夫妻中选择一人出席,如果两个人有矛盾的话,
则假如其中一个人出席,则只能另一个人的妻子出席,同时假如第一个人不出席,则他的妻子和另一个人必须同时出席,而且是必然关系,
所以我们就把这些关系连边,就形成了一个有向图,环(强连通分量)里的点是一定会同时出席的,所以我们对图进行缩点,如果
发现夫妻在同一个强连通分量中,就说明不能满足条件了。存图的话我是2*x和2*x+1表示一对夫妻。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2100; struct edge { int f,t, nxt; }e[maxn*maxn]; int hd[maxn], tot; void add(int f, int t) { e[++tot] = { f,t,hd[f] }; hd[f] = tot; } int n,m; int low[maxn], dfn[maxn], cnt; int stk[maxn], sk,instk[maxn],col[maxn], colnum; void init() { memset(dfn, 0, sizeof(dfn)); memset(col, 0, sizeof(col)); memset(hd, 0, sizeof(hd)); tot = colnum = cnt = 0; } void dfs(int u) {//缩点模板 low[u] = dfn[u] = ++cnt; stk[++sk] = u; instk[u] = 1; for (int i = hd[u]; i; i = e[i].nxt) { int v = e[i].t; if (!dfn[v]) { dfs(v); low[u] = min(low[u], low[v]); } else if(instk[v]){ low[u] = min(low[u], dfn[v]); } } if (low[u] == dfn[u]) { colnum++; while (1) { int v = stk[sk--]; instk[v] = 0; col[v] = colnum; if (v == u)break; } } } int main() { //freopen("test.txt", "r", stdin); while (~scanf("%d%d", &n, &m)) { init(); for (int i = 1; i <= m; i++) { int a1, a2, c1, c2; scanf("%d%d%d%d", &a1, &a2, &c1, &c2); add(a1 * 2 + c1, a2 * 2 +c2^1);//2*x和2*x+1代表一对夫妻 //add(a1 * 2 + c1^1, a2 * 2 +c2);//为什么这样建图不行呢? add(a2 * 2 + c2, a1 * 2 + c1^1);//必须要反着选一个来连边 } for (int i = 0; i < 2 * n; i++) { if (!dfn[i]) { dfs(i); } } int f = 1; for (int i = 0; i < n; i++) { if (col[i * 2] == col[i * 2 + 1]) {//如果夫妻再一个SCC,说明夫妻必须同时出席,不能满足 f = 0; break; } } if (f) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }