本文共 2643 字,大约阅读时间需要 8 分钟。
问题
n n n个布尔变量, m m m组限制,每组限制形如 a , x , b , y a,x,b,y a,x,b,y
表示 a = x a=x a=x和 b = y b=y b=y一定有一个成立(其中 x , y x,y x,y是布尔值)
求出一组可行解,或者说明这是不可能的
拆点,原图中的点 i i i表示 f a l s e false false, i + n i+n i+n表示 t r u e true true
对于 a = t r u e ∣ ∣ b = = f a l s e a=true||b==false a=true∣∣b==false一定成立其中的至少一个
如果 a a a的值为 f a l s e false false那么 b b b一定是 f a l s e false false
对应的,我们连边 a − > b a->b a−>b
如果 b b b的值为 t r u e true true那么 a a a一定是 t r u e true true
对应的,我们连边 b + n − > a + n b+n->a+n b+n−>a+n
这样有什么好处…看个图
比如这里 x 1 x_1 x1代表的 t r u e true true和 f a l s e false false居然在一个强连通里面,结合边的意义就是说若 x 1 x_1 x1是 t r u e true true, 可以推断 x 1 x_1 x1是 f a l s e false false,所以矛盾,即 x 1 x_1 x1不是 t r u e true true
若 x 1 x_1 x1是 f a l s e false false, 可以推断 x 1 x_1 x1是 t r u e true true,所以矛盾,即 x 1 x_1 x1不是 f a l s e false false
所以 x 1 x_1 x1啥也不是,无解。
所以判断有没有解,只需要看一下同一个点的两个状态是否在同一个强连通中即可
在这副图中,如何构造解??
显然如果取 x 1 = f a l s e x_1=false x1=false可以推断 x 1 = t r u e x_1=true x1=true,所以我们应该选择 x 1 = t r u e x_1=true x1=true
也就是两个状态中,被指向的那个状态
其实就是 D A G DAG DAG中的拓扑序,而 t a r j a n tarjan tarjan算法的 s c c scc scc是由栈形成的
一定是经过了前驱的强连通分量到达被指向的强连通分量,然后弹栈
所以 s c c scc scc编号越小的,是被指向的强连通,我们应该选择
#includeusing namespace std;const int maxn = 4e6+10;struct edge{ int to,nxt;}d[maxn]; int head[maxn],cnt=1;void add(int u,int v){ d[++cnt] = ( edge ){ v,head[u]},head[u] = cnt;}int n,m;int low[maxn],dfn[maxn],scc[maxn],vis[maxn],stac[maxn],sc,id,top;void tarjan(int u){ dfn[u] = low[u] = ++id; stac[++top] = u; vis[u] = 1; for(int i=head[u];i;i=d[i].nxt ) { int v = d[i].to; if( !dfn[v] ) tarjan(v),low[u] = min( low[u],low[v] ); else if( vis[v] ) low[u] = min( low[u],dfn[v] ); } if( dfn[u] == low[u] ) { int temp; ++sc; while( temp=stac[top--] ) { vis[temp] = 0, scc[temp] = sc; if( temp==u ) break; } }}int main(){ cin >> n >> m; for(int i=1;i<=m;i++) { int a,x,b,y; scanf("%d%d%d%d",&a,&x,&b,&y); if( x==0 && y ==0 ) add( a+n,b),add(b+n,a);//一方为真,另一方一定是假 else if( x==0&&y==1 ) add( a+n,b+n ),add( b,a ); else if( x==1&&y==0 ) add( a,b ),add( b+n,a+n ); else if( x==1 && y==1 ) add( a,b+n ),add( b,a+n ); } for(int i=1;i<=n+n;i++) if( !dfn[i] ) tarjan(i); for(int i=1;i<=n;i++) if( scc[i]==scc[i+n] ) { printf("IMPOSSIBLE\n"); return 0; } puts("POSSIBLE"); for(int i=1;i<=n;i++) { if( scc[i]>scc[i+n] ) printf("1 "); else printf("0 "); } return 0;}
转载地址:https://issue-is-vegetable.blog.csdn.net/article/details/115384396 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!