通用做法:拆点+Tarjan求强连通分量。将点(i)拆为(i)和(i+n),分别表示(i)为假以及(i)为真。注意这个顺序不能搞反,否则求可行解的时候会出错。
连边:
本题中给出的命题为:“(x)为(a)或(y)为(b)”。以“(x)为真或(y)为假”为例,连边时作以下考虑:
-
若(x)为假,则(y)必须为假,命题才能成立,故连边(x→y)
-
若(y)为真,则(x)必须为真,命题才能成立,故连边(y+n→x+n)
连边完成。
显然当(i)与(i+n)在同一个强连通分量中时,无论怎样取值都无法满足全部命题,此时无解。
当输出布尔变量(i)的可行解时,只需输出强连通分量编号较小的那一个取值即可,即:
for(int i=1;i<=n;i++){
if(sccno[i+n]<sccno[i]) cout<<"1 ";
else cout<<"0 ";
}