这题只判断可行性,不用输出解,应该是2-sat入门题里最水的一道....
代码:
//n个元素。i=0~n-1. //i表示0、i+n表示1、i+2n表示0'、i+3n表示1'。 //1wa。这题竟然有多组数据。... #include<cstdio> #include<cstring> #include<iostream> using namespace std; #define MAXN 4002 //4倍的点 //#define MAXM 8000002 //n*n/2 #define MAXM 30000100 //??? struct node{ int u, v; }a[MAXM]; int first[MAXN], next[MAXM], idx; //idx 边下标 int n; //n对夫妻 int m; //m对矛盾关系 void addedge(int u, int v) { a[idx].u = u, a[idx].v = v; next[idx] = first[u]; first[u] = idx++; } int dfn[MAXN], low[MAXN]; int stack[MAXN], ins[MAXN]; int belong[MAXN], cnt; //属于什么连通分量 int top, num; void tarjin(int u) { dfn[u] = low[u] = ++num; ins[u] = 1; stack[top++] = u; for(int e=first[u]; e!=-1; e=next[e]) { int v = a[e].v; if(!dfn[v]) { tarjin(v); low[u] = min(low[u], low[v]); } else if(ins[v]) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { while(1) { int v = stack[--top]; ins[v] = 0; belong[v] = cnt; //标记分量belong if(u == v) break; } cnt++; } } int solve() { for(int i=0; i<4*n; i++) //4*n 总点数 { if(!dfn[i]) tarjin(i); } for(int i=0; i<2*n; i++) //遍历 女、男 { if(belong[i] == belong[i+2*n]) { return 0; } } return 1; } int read() { memset(belong, 0, sizeof(belong)); memset(dfn, 0, sizeof(dfn)); memset(first, -1, sizeof(first)); memset(ins, 0, sizeof(ins)); num = cnt = 0; top = 0; if(scanf("%d%d", &n, &m)!=EOF) { idx = 0; //初始化边编号 for(int i=0; i<n; i++) { addedge(i, i+3*n); addedge(i+3*n, i); addedge(i+n, i+2*n); addedge(i+2*n, i+n); } for(int i=0; i<m; i++) { int a1, a2, c1, c2; scanf("%d%d%d%d", &a1, &a2, &c1, &c2); if(c1) a1+=n; if(c2) a2+=n; //下标转化。女->男 addedge(a1, a2+2*n); addedge(a2, a1+2*n); } return 1; } else return 0; } int main() { while(read()) { if(solve()) printf("YES\n"); else printf("NO\n"); } }