题意:给定一个有n个点m条边的有向图,每个边给一个运算符op(AND, OR, XOR)以及一个权值c,问是否能将每个点的值赋成Xi(0或1)后,使得每条边满足Xa op Xb = c。
分析:
1、经典的2-SAT问题。白书324页。
进行强连通分量分解后,若x和¬x在同一个强连通分量中,则无解。
2、关键在于加边:
(1)
A AND B = 1 !A->A !B->B
A AND B = 0 A->!B B->!A
(2)
A OR B = 1 !A->B !B->A
A OR B = 0 A->!A B->!B
(3)
A XOR B = 1 A->!B !B->A !A->B B->!A
A XOR B = 0 A->B B->A !A->!B !B->!A
3、对A AND B = 1的解释:
A和B都必须取1,
对于x和¬x,如果一定要取x,则连边¬x —> x。
4、a表示¬x,a+n表示x。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cctype> #include<cmath> #include<iostream> #include<sstream> #include<iterator> #include<algorithm> #include<string> #include<vector> #include<set> #include<map> #include<stack> #include<deque> #include<queue> #include<list> #define lowbit(x) (x & (-x)) const double eps = 1e-8; inline int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a > b ? 1 : -1; } typedef long long LL; typedef unsigned long long ULL; const int INT_INF = 0x3f3f3f3f; const int INT_M_INF = 0x7f7f7f7f; const LL LL_INF = 0x3f3f3f3f3f3f3f3f; const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f; const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1}; const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1}; const int MOD = 1e9 + 7; const double pi = acos(-1.0); const int MAXN = 1000 + 10; const int MAXT = 10000 + 10; using namespace std; int N; vector<int> G[MAXN << 1]; vector<int> rG[MAXN << 1]; vector<int> vs; bool used[MAXN << 1]; int cmp[MAXN << 1]; void addedge(int from, int to){ G[from].push_back(to); rG[to].push_back(from); } void dfs(int v){ used[v] = true; for(int i = 0; i < G[v].size(); ++i){ if(!used[G[v][i]]) dfs(G[v][i]); } vs.push_back(v); } void rdfs(int v, int k){ used[v] = true; cmp[v] = k; for(int i = 0; i < rG[v].size(); ++i){ if(!used[rG[v][i]]) rdfs(rG[v][i], k); } } int scc(){ memset(used, 0, sizeof used); vs.clear(); for(int i = 0; i < 2 * N; ++i){ if(!used[i]) dfs(i); } memset(used, 0, sizeof used); int k = 0; for(int i = vs.size() - 1; i >= 0; --i){ if(!used[vs[i]]) rdfs(vs[i], k++); } return k; } int main(){ int M; scanf("%d%d", &N, &M); while(M--){ int a, b, c; string s; scanf("%d%d%d", &a, &b, &c); cin >> s; if(s == "AND"){ if(c == 1){ addedge(a, a + N); addedge(b, b + N); } else{ addedge(a + N, b); addedge(b + N, a); } } else if(s == "OR"){ if(c == 1){ addedge(a, b + N); addedge(b, a + N); } else{ addedge(a + N, a); addedge(b + N, b); } } else{ if(c == 1){ addedge(a, b + N); addedge(a + N, b); addedge(b, a + N); addedge(b + N, a); } else{ addedge(a, b); addedge(a + N, b + N); addedge(b, a); addedge(b + N, a + N); } } } scc(); for(int i = 0; i < N; ++i){ if(cmp[i] == cmp[i + N]){ printf("NO\n"); return 0; } } printf("YES\n"); return 0; }