CodeForces - 668E Little Artem and 2-SAT

题意

给出两个2-sat,如果存在使其中一组成立,另一组不成立的变量取值,输出之,否则输出SIMILAR

题解

按照2-sat的正常操作建边
我们可以跑一发floyd
注意一定要连一个自己到自己的边
(前来更新,根据某dalao指出https://blog.csdn.net/qq_34454069,其实可以不用,后面判断的时候看一下i、j相不相等就可以了)
然而,有的时候,某个变量会有特定的取值(真或假),(例如有从i到!i的路径)此时我们就需要连边来保证,否则可能会出现两个2-sat都保证该变量的取值,却连边不同的情况,进而影响我们最终出解

然后呢,对于这两个2-sat所得到的邻接矩阵,如果存在路径u->v存在于有且只有一个矩阵中(不妨设为存在于f中不存在于g中)
那么我们令u=1,v=0,那么f就为假,g就为真
就达成了目标
如果不存在,那么输出SIMILAR

分析时间复杂度,主要体现在floyd处, O(2N3)=O(8N3) O ( ( 2 · N ) 3 ) = O ( 8 · N 3 ) ,N是1000,所以会TLE
然而我们有神器bitset,复杂度除以32,就可以过了。(时间限制3s)

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int N=2010;
int n;
int ans[N];
void watch(bitset a){
    string s=a.to_string();
    reverse(s.begin(),s.end());
    cout<struct _2sat{
    bitset g[N];//表示推出关系
    int m;
    void debug(){
        for(int i=0;i<2*n;i++)
            watch(g[i]);
    }
    int get(int x){
        if(x>0)
            return x*2-2;//如果是正数,返回一个偶数值
        else
            return -x*2-1;//如果是负数,返回一个奇数值
    }
    void read(){
        while(m--){
            int x,y;
            scanf("%d%d",&x,&y);
            x=get(x),y=get(y);//连边
            g[x^1].set(y);
            g[y^1].set(x);
            //debug();
        }
        //debug();
    }
    void calc(){//本质上等同一个floyd
        //debug();
        for(int i=0;i<2*n;i++)
            for(int j=0;j<2*n;j++)
                if(g[j][i])
                    g[j]|=g[i];
        //debug();
    }
    void solve(){
        calc();
        for(int i=0;i2;i++)
            if(g[i][i^1]){//如果存在着i->!i,则不能选择i
                for(int j=0;j2;j++){
                    g[i].set(j);
                    g[j].set(i^1);
                }
            }
        calc();
    }
    void dfs(int v){//通过推出关系找出答案
        if(ans[v]!=-1)
            return ;
        ans[v]=1,ans[v^1]=0;
        for(int i=0;i2;i++)
            if(g[v][i])
               ans[i]=1,ans[i^1]=0;
    }
    void getans(int u,int v){//由于有一个包含u->v,另一个没有,那么我们就令u为1,v为0,就可满足题意
        dfs(u);
        dfs(v^1);
        for(int i=0;i2;i++)//其他的就随便令值
            if(ans[i]==-1&&!g[i][i^1])
                dfs(i);
    }
}F,G;
int main()
{
    scanf("%d%d%d",&n,&F.m,&G.m);
    F.read(),F.solve();
    G.read(),G.solve();
    //F.debug(),G.debug();
    memset(ans,-1,sizeof ans);
    for(int i=0;i2;i++)
    {
        for(int j=0;j2;j++)
        {
            if (i!=j&&F.g[i][j]!=G.g[i][j])
            {
                if (F.g[i][j])
                    G.getans(i,j);
                else
                    F.getans(i,j);
                for(int k=0;kprintf("%d ",ans[k*2]);//偶数中储存的是该变量对应的答案
                puts("");
                return 0;
            }
        }
    }
    puts("SIMILAR");
}

你可能感兴趣的:(图论)