这题只判断可行性,不用输出解,应该是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");
}
}