zoukankan      html  css  js  c++  java
  • @codeforces


    @description@

    给定两个 2-sat 问题,询问两个问题的解集是否相同。

    如果不相同,构造一组解 {xi},使得这个解是其中一个问题的解同时不是另一个问题的解。

    原题链接。

    @solution@

    如果两者解集都为空,那么解集相同。
    如果两者只有一个解集为空,则取另一个问题的任意解即可。

    如果都有解,先跑个 bitset 优化的传递闭包,方便接下来的处理。

    此时有一些变量的值是确定的(即可以从该变量的 0/1 状态到达该变量的 1/0 状态)。
    如果有一个变量在问题 A 中确定而在问题 B 中不确定,则强制令 B 中该变量的值为 A 中值取反,暴力求此时 B 中的任意解。
    如果有一个变量在两个问题中都确定但是确定的值不同,直接取问题 A 的任意解即可。

    现在确定的变量都长一样了。但是不确定的变量可能相互制约,所以还是不能断定两个问题解集相同。

    如果两个不确定的变量对应的结点 u, v,在问题 A 中有边相连 u -> v,在问题 B 中没有边相连,我们就可以构造出一组解。
    在问题 B 中强制令 u 为真,v 为假,构造出 B 的任意解,该解在 A 中一定不成立。

    @accepted code@

    #include <cstdio>
    #include <bitset>
    #include <algorithm>
    using namespace std;
    
    const int MAXN = 2000;
    
    bitset<MAXN>G[2][MAXN]; int n;
    
    int abs(int x) {return x >= 0 ? x : -x;}
    
    bool f[2]; int a[2][MAXN + 5];
    void get(int o) {
    	for(int i=0;i<n;i++) {
    		if( a[o][i] == -1 ) {
    			for(int j=0;j<n;j++)
    				if( (a[o][j] == 0 && G[o][i<<1|1][j<<1|1]) || (a[o][j] == 1 && G[o][i<<1|1][j<<1]) ) {
    					a[o][i] = 0;
    					break;
    				}
    			if( a[o][i] == -1 ) a[o][i] = 1;
    		}
    		printf("%d ", a[o][i]);
    	}
    	exit(0);
    }
    
    int main() {
    	int m[2]; scanf("%d%d%d", &n, &m[0], &m[1]);
    	for(int o=0;o<2;o++) {
    		for(int i=1;i<=m[o];i++) {
    			int a, b; scanf("%d%d", &a, &b);
    			int p = (a < 0), q = (b < 0); a = abs(a) - 1, b = abs(b) - 1;
    			G[o][a<<1|p][b<<1|(!q)] = true, G[o][b<<1|q][a<<1|(!p)] = true;
    		}
    		for(int i=0;i<(n<<1);i++) G[o][i][i] = true;
    		for(int k=0;k<(n<<1);k++)
    			for(int i=0;i<(n<<1);i++)
    				if( G[o][i][k] ) G[o][i] |= G[o][k];
    		for(int i=0;i<n;i++) {
    			if( G[o][i<<1][i<<1|1] && G[o][i<<1|1][i<<1] ) {
    				f[o] = true;
    				break;
    			}
    			else if( G[o][i<<1][i<<1|1] ) a[o][i] = 1;
    			else if( G[o][i<<1|1][i<<1] ) a[o][i] = 0;
    			else a[o][i] = -1;
    		}
    	}
    	if( f[0] && f[1] ) puts("SIMILAR");
    	else if( f[0] ) get(1);
    	else if( f[1] ) get(0);
    	else {
    		for(int i=0;i<n;i++)
    			if( a[0][i] != a[1][i] ) {
    				if( a[0][i] == -1 ) a[0][i] = (!a[1][i]), get(0);
    				else if( a[1][i] == -1 ) a[1][i] = (!a[0][i]), get(1);
    				else get(0);
    				return 0;
    			}
    		for(int i=0;i<n;i++)
    			for(int j=0;j<n;j++) {
    				if( a[0][i] == -1 && a[0][j] == -1 ) {
    					if( G[0][i<<1|1][j<<1|1] != G[1][i<<1|1][j<<1|1] ) {
    						if( G[0][i<<1|1][j<<1|1] == 0 )
    							a[0][i] = 1, a[0][j] = 0, get(0);
    						else a[1][i] = 1, a[1][j] = 0, get(1);
    						return 0;
    					}
    					else if( G[0][i<<1|1][j<<1] != G[1][i<<1|1][j<<1] ) {
    						if( G[0][i<<1|1][j<<1] == 0 )
    							a[0][i] = 1, a[0][j] = 1, get(0);
    						else a[1][i] = 1, a[1][j] = 1, get(1);
    						return 0;
    					}
    					else if( G[0][i<<1][j<<1|1] != G[1][i<<1][j<<1|1] ) {
    						if( G[0][i<<1][j<<1|1] == 0 )
    							a[0][i] = 0, a[0][j] = 0, get(0);
    						else a[1][i] = 0, a[1][j] = 0, get(1);
    						return 0;
    					}
    					else if( G[0][i<<1][j<<1] != G[1][i<<1][j<<1] ) {
    						if( G[0][i<<1][j<<1] == 0 )
    							a[0][i] = 0, a[0][j] = 1, get(0);
    						else a[1][i] = 0, a[1][j] = 1, get(1);
    						return 0;
    					}
    				}
    			}
    		puts("SIMILAR");
    	}
    }
    

    @details@

    注意有一些边界情况,预先给每个结点连个自环。

  • 相关阅读:
    web网站开发反面教材
    phpstudy 做的后台长时间运行的脚本,设置了脚本运行时间还是40秒就返回500,用的apache2.4.39
    PHP_EOL
    web文件下载,a标签文件下载,php文件下载
    邮件发送
    网站调用qq第三方登录
    微信Pcweb登录简介
    JqueryOn绑定事件方法介绍
    php+ajax文件上传
    php操作数组函数
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12244194.html
Copyright © 2011-2022 走看看