题面
题目描述
有 n n n 个布尔变量 x 1 x_1 x1 ~ x n x_n xn,满足 m m m 个形如 x i = t r u e / f a l s e x_i=true/false xi=true/false 或 x j = t r u e / f a l s e x_j=true/false xj=true/false 的条件 。
输入
第一行两个整数 n n n 和 m m m,意义如题面所述。接下来的 m m m 行,每行四个整数, x , a , y , b x,a,y,b x,a,y,b ( 1 ≤ x , y ≤ n a , b ∈ { 0 , 1 } 1\leq x,y\leq n\ \ a,b \in \{0,1\} 1≤x,y≤n a,b∈{0,1})。
输出
无解输出
I
M
P
O
S
S
I
B
L
E
IMPOSSIBLE
IMPOSSIBLE。
有解输出
P
O
S
S
I
B
L
E
POSSIBLE
POSSIBLE。并输出构造出来的解。
采用
S
p
e
c
i
a
l
J
u
d
g
e
Special \ Judge
Special Judge。
样例
输入
3 1
1 1 3 0
输出
POSSIBLE
0 0 0
题解
连边
- 定义点 x x x 表示 ( x − ( x > n ) ∗ n ) = ( x > n ) (x-(x>n)*n)=(x>n) (x−(x>n)∗n)=(x>n),也就是:
- 如果点 x ≤ n x\leq n x≤n,则代表第 x x x 个数为 0 0 0。
- 如果点 x ≥ n + 1 x\geq n+1 x≥n+1,则代表第 x − n x-n x−n 个数为 1 1 1。
- 定义边 ( x , y x,y x,y) 由 ( x − ( x > n ) ∗ n ) = ( x > n ) (x-(x>n)*n)=(x>n) (x−(x>n)∗n)=(x>n) 可以推出 ( y − ( y > n ) ∗ n ) = ( y > n ) (y-(y>n)*n)=(y>n) (y−(y>n)∗n)=(y>n)。
对于条件 (
x
=
a
∣
∣
y
=
b
x=a||y=b
x=a∣∣y=b),我们可以转化为:
x
=
a
x
o
r
1
→
y
=
b
x=a\ xor\ 1\rightarrow y=b
x=a xor 1→y=b
y
=
b
x
o
r
1
→
x
=
a
y=b\ xor\ 1\rightarrow x=a
y=b xor 1→x=a
由此我们就知道了该怎么连边。
add(x + (a ^ 1) * n,y + b * n);
add(y + (b ^ 1) * n,x + a * n);
判无解
于是连完后,我们跑一遍 t a r j a n tarjan tarjan,求出其中的强连通分量,如果 x x x 和 x + n x+n x+n 同处于一个强连通分量内,那么显然无解。原因很显然,这意味着我们从 x = 0 x=0 x=0 推出了 x = 1 x = 1 x=1。
构造值
接下来是构造值的问题。
我用的是小蓝书的第二种方法,这里就不赘述原理了。
代码
#include<cstdio>
#include<iostream>
using std::min;
const int N = 2e6 + 5;
struct edge {
int next,to;
}a[N << 1];
int head[N],opp[N],n,m,a_size = 1;
inline void add(int u,int v) {
a[++a_size] = (edge){head[u],v};
head[u] = a_size;
}
int dfn[N],low[N],sta[N],c[N],top = 0,cnt = 0,num = 0;
bool ins[N];
void tarjan(int x) {
dfn[x] = low[x] = ++num;
sta[++top] = x; ins[x] = true;
for(int i = head[x]; i; i = a[i].next) {
int y = a[i].to;
if(!dfn[y]) {
tarjan(y);
low[x] = min(low[x],low[y]);
}
else if(ins[y])
low[x] = min(low[x],dfn[y]);
}
if(dfn[x] == low[x]) {
int y; cnt++;
do {
y = sta[top--]; ins[y] = false;
c[y] = cnt;
}while(x != y);
}
}
inline int read() {
int x = 0,flag = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')flag = -1;ch = getchar();}
while(ch >='0' && ch <='9'){x = (x << 3) + (x << 1) + ch - 48;ch = getchar();}
return x * flag;
}
int main() {
n = read(),m = read();
for(int i = 1; i <= m; i++) {
int x = read(),a = read(),y = read(),b = read();
add(x + (a ^ 1) * n,y + b * n);
add(y + (b ^ 1) * n,x + a * n);
} n <<= 1;
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
n >>= 1;
for(int i = 1; i <= n; i++)
if(c[i] == c[i + n]) {puts("IMPOSSIBLE"); return 0;}
puts("POSSIBLE");
for(int i = 1; i <= n; i++)
printf("%d ",c[i] > c[n + i]);
return 0;
}