2-SAT

2-SAT

HDU 3062

有n对夫妻被邀请参加一个聚会,因为场地的问题,每对夫妻中只有1人可以列席。在2n 个人中,某些人之间有着很大的矛盾(当然夫妻之间是没有矛盾的),有矛盾的2个人是不会同时出现在聚会上的。有没有可能会有n 个人同时列席?

因为一对夫妻中只有一个可以出席, 所以可以将女方出席看成命题 \(i_0\) 男方出席看成命题 \(i_1\) 然后两个命题护卫反命题

\(i_0\)\(j_1\) 有矛盾, 并且 \(i_0\) 为真 那么 \(j_0\) 一定为真 反着同理

回到这个夫妻的问题

假如 \(a_0\)\(b_0\) 有矛盾, 那么 \(a_0\) 一定连向 \(b_1\)

然后就可以形成一个图

考虑如果图上有环怎么办, 不用管

那么什么情况下不可以呢?

就是如果图上的一个强连通分量中同时有夫妻中的两个人

那么就意味着要想选\(A_0\)就必须选\(A_1\)显然不行

但是为什么必须要在同一个强连通分量中呢?

因为如果只是单纯的\(A_0\to ...\to A_1\)我们可以直接从\(A_1\)开始行走

为什么只要没有任何一对夫妻在同一个强连通分量中就成功了呢?

因为建立的图是矛盾的图, 不是总情况的图, 所以就意味着没有建立边的两个点是可以行走的, 所以只要不是矛盾就一定是联通的

代码(使用Kosaraju用来计算强连通分量)

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#include<iomanip>
#include<vector>
using namespace std;
inline int read() {int x=0,f=1; char ch=getchar();while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar();}while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;}
const int N=2000+5;
vector<int> G[N],rG[N];
void addEdge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}
int n,m,vis[N],sccno[N],cnt;
vector<int> S;
void dfs1(int u){
    if(vis[u]) return;
    vis[u]=1;
    for(int i=0;i<G[u].size();i++) dfs1(G[u][i]);
    S.push_back(u);
}
void dfs2(int u){
    if(sccno[u]) return;
    sccno[u] = cnt;
    for(auto v:rG[u]) dfs2(v);
}
bool twoSAT(){
    for(int i=1;i<=n;i++)
        if(sccno[i]==sccno[i+n])
            return false;
    return true;
}
signed main() {
    while( scanf("%d%d",&n,&m)!=EOF&&(n+m)){
    // n=read(),m=read();
        for(int i=0;i<=2*n;i++){
            G[i].clear();
            rG[i].clear();
        }
        cnt=0;memset(sccno,0,sizeof(sccno));memset(vis,false,sizeof(vis));S.clear();
        while(m--) {
            int x=read()+1,y=read()+1,xVal=read(),yVal=read();
            if(xVal==0&&yVal==0){//x为0或y为0
                addEdge(x+n,y);//x为0,y为1
                addEdge(y+n,x);//y为0,x为1
            }
            else if(xVal==0&&yVal==1){//x为0或y为1
                addEdge(x+n,y+n);//x为0,y为0
                addEdge(y,x);//y为1,x为1
            }
            else if(xVal==1&&yVal==0){//x为1或y为0
                addEdge(x,y);//x为1,y为1
                addEdge(y+n,x+n);//y为0,x为0
            }
            else if(xVal==1&&yVal==1){//x为1或y为1
                addEdge(x,y+n);//x为1,y为0
                addEdge(y,x+n);//y为1,x为0
            }
        }

        // for(int i=1;i<=2*n;i++){
        //     cout<<i<<": ";
        //     for(auto v:G[i]) cout<<v<<' ';
        //     cout<<endl;
        // }
        // for(int i=1;i<=2*n;i++){
        //     cout<<i<<": ";
        //     for(auto v:rG[i]) cout<<v<<' ';
        //     cout<<endl;
        // }

        for(int i=1;i<=2*n;i++) if(!vis[i]) dfs1(i);
        // for(auto v:S) if(vis[v]) dfs2(v);
        for(int i=2*n-1; i>=0; i--){
            if(!sccno[S[i]]){
                cnt++;
                dfs2(S[i]);
            }
        }

        // for()

        bool flag=twoSAT();
        if(!flag) printf("NO\n");
        else printf("YES\n");
    }
    return 0;
}
posted @ 2025-08-11 20:10  Chen1098  阅读(7)  评论(0)    收藏  举报