题解:
根据矛盾关系构造布尔公式。
令 0~n-1 表示妻子, n~2*n-1 表示丈夫
A1 C1
A2 C2
如果C1为0,C2为0,对应的布尔公式为 (A1+n)V(A2+n)
如果C1为0,C2为1,对应的布尔公式为 (A1+n)V(A2)
如果C1为1,C2为0,对应的布尔公式为 (A1)V(A2+n)
如果C1为1,C2为1,对应的布尔公式为 (A1)V(A2)
判断是否存在一组解,使得所有满足条件的合取范式 ((A1+n)V(A2+n))∧((A1+n)V(A2))∧((A1)V(A2+n))∧((A1)V(A2)) 的值为真;
如果存在,输出YES,反之,输出NO.
讲析取式转化成两个蕴含式,以此构图,然后进行强连通分量分解,求出所属强连通分量的拓扑序。
如果有 scc[i] == scc[n+i] 则无解,输出NO,反之,一定有解,输出YES。
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 #define pb push_back 7 #define mem(a,b) (memset(a,b,sizeof a)) 8 const int maxn=1e3+50; 9 10 int n,m; 11 int scc[2*maxn]; 12 bool vis[2*maxn]; 13 vector<int >vs; 14 vector<int >G[2*maxn],rG[2*maxn]; 15 void addEdge(int u,int v) 16 { 17 G[u].pb(v); 18 rG[v].pb(u); 19 } 20 void Dfs(int u) 21 { 22 vis[u]=true; 23 for(int i=0;i < G[u].size();++i) 24 { 25 int to=G[u][i]; 26 if(!vis[to]) 27 Dfs(to); 28 } 29 vs.pb(u); 30 } 31 void rDfs(int u,int k) 32 { 33 scc[u]=k; 34 vis[u]=true; 35 for(int i=0;i < rG[u].size();++i) 36 { 37 int to=rG[u][i]; 38 if(!vis[to]) 39 rDfs(to,k); 40 } 41 } 42 void SCC() 43 { 44 mem(vis,false); 45 vs.clear(); 46 for(int i=0;i < 2*n;++i) 47 if(!vis[i]) 48 Dfs(i); 49 int k=0; 50 mem(vis,false); 51 for(int i=vs.size()-1;i >= 0;--i) 52 { 53 int u=vs[i]; 54 if(!vis[u]) 55 rDfs(u,++k); 56 } 57 } 58 void Init() 59 { 60 for(int i=0;i < 2*maxn;++i) 61 G[i].clear(),rG[i].clear(); 62 } 63 int main() 64 { 65 while(~scanf("%d%d",&n,&m)) 66 { 67 Init(); 68 for(int i=1;i <= m;++i) 69 { 70 int a1,c1; 71 int a2,c2; 72 scanf("%d%d%d%d",&a1,&a2,&c1,&c2); 73 int x=a1+(c1 == 0 ? 1:0)*n;//矛盾关系对应的布尔公式为(xVy),转化成两个蕴含式即为有向图中对应的边 74 int y=a2+(c2 == 0 ? 1:0)*n; 75 addEdge((x >= n ? x-n:x+n),y); 76 addEdge((y >= n ? y-n:y+n),x); 77 } 78 SCC(); 79 bool flag=false; 80 for(int i=0;i < n;++i) 81 if(scc[i] == scc[i+n]) 82 flag=true; 83 if(flag) 84 printf("NO\n"); 85 else 86 printf("YES\n"); 87 } 88 }