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;
}

 

posted @ 2021-04-03 15:05  cono奇犽哒  阅读(109)  评论(0)    收藏  举报