题意:
给你N个命题,M个条件,每个条件都是一个析取式,问你最少需要添加多少个析取式子能够使得全部条件无法同时成立,你能添加的式子都不带‘非’运算符。
题目分析:
将每个命题本身和他的非建一个2N个点的图,那么每个条件都能建立以下边:
按照以上方式建图之后,要使得无法全部条件全部成立,就说明存在一对点A和-A,互相可达。
我们能加的边只有第一种(A V B),也可以直接从-A连到A(条件A V A),注意到往右边连边的只有第四种条件(-A V -B),所以如果不存在第四种条件显然无解。
我们枚举每个点为起点,标记它能到达的点,然后查每组A,-A之间的关系,答案只有4种情况:
0:存在A与-A能互相到达
1:存在A能到达-A,而-A不能到达A,加入条件(A V A)
2:没有任何一个A能到达-A,但是存在条件(-A V -B),我们加入条件(A V A)和(B V B)即可
无解:不存在第四种条件(-A V -B)。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n, m;
struct edge{
int v,next;
}e[16010];
int head[4010], cnt;
inline void add(int u,int v){
e[cnt] = (edge){v,head[u]}, head[u] = cnt++;
}
bool to[4010][4010];
void bfs(int s){
queue<int>que; que.push(s);
while(que.size()){
int u = que.front(); que.pop();
for(int i = head[u]; ~i; i = e[i].next){
if(!to[s][e[i].v]){
to[s][e[i].v] = 1;
que.push(e[i].v);
}
}
}
}
int main(){
memset(head, -1, sizeof head);
scanf("%d%d",&n,&m);
int ans = 3;
for(int i = 1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
if(u > 0 && v > 0){
add(v+n, u);
if(u != v) add(u+n, v);
}else if(u < 0 && v < 0){
ans = 2;
u = -u, v = -v;
add(v, u+n);
if(u != v) add(u, v+n);
}else{
if(u < 0)swap(u,v);
v = -v;
if(u == v) continue;
add(v, u);
add(u+n, v+n);
}
}
if(ans == 3){
puts("-1"); return 0;
}
for(int i = 1;i<=n*2;i++)
bfs(i);
for(int i = 1;i<=n;i++){
if(to[i][i+n]){
if(to[i+n][i]) ans = 0;
else ans = min(ans, 1);
}
}
if(ans == 3)
puts("-1");
else
printf("%d\n",ans);
return 0;
}