UVALive 6067 Bit Magic 通过三个位运算约束求是否有解 2-sat

有如下的代码:
现在给定b[N][N],求是否存在a[N]

void calculate(int a[N], int b[N][N]) {
    for (int i = 0; i < N; ++i) {
    for (int j = 0; j < N; ++j) {
        if (i == j) b[i][j] = 0;
        else if (i % 2 == 1 && j % 2 == 1) b[i][j] = a[i] | a[j];
        else if (i % 2 == 0 && j % 2 == 0) b[i][j] = a[i] & a[j];
        else b[i][j] = a[i] ^ a[j];
        }
    }
}

经典的2-sat题目。。跟POJ 3678差不多。。只不过是把每一位都拿出来比较了。。
用a’来代表该变量取0,a来代表该变量取1

1.a&b == 1 a’->a b’->b
2.a&b == 0 a->b’ b->a’
3.a|b == 1 a’->b b’->a
4.a|b == 0 a->a’ b->b’
5.a^b == 1 a<->b’ b<->a’
6.a^b == 0 a<->b a’<->b’

照此种方式建图。。。对于每一位。判断是否存在解。
若是想求任意解的话,也可以求出。
题目只要求判断是否存在。
代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 510;
struct Edge {
    int to,next;
    Edge(){}
    Edge(int _to,int _next):to(_to),next(_next){}
}e[MAXN*MAXN*4+1100];
int head[MAXN*3],tot;
void init(){
    memset(head,-1,sizeof(head)); tot=0;
}
void AddEdge(int u,int v){
    e[tot]=Edge(v,head[u]);
    head[u]=tot++;
    //extern void print(int u,int v);
    //print(u,v);
}
int dfn[MAXN*3],low[MAXN*3],sta[MAXN*3],bleg[MAXN*3];
int times,top;
void tarjan(int u){
    dfn[u]=low[u]=++times;
    sta[++top]=u;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!bleg[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u]){
        ++bleg[0];
        do {
            bleg[sta[top]]=bleg[0];
        }while(sta[top--]!=u);
    }
}
void print(int u,int v){
    printf("%d%c-->%d%c\n",u>>1,(u&1)?'\'':' ',v>>1,(v&1)?'\'':' ');
}
int b[MAXN][MAXN],n;
int main()
{
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&b[i][j]);
        int flag=0;
        for(int i=0;i<n;i++){
            if(b[i][i]!=0)flag=1;
            for(int j=i+1;j<n;j++){
                if(b[i][j]!=b[j][i])flag=1;
            }
        }
        for(int k=0;k<32&&!flag;k++){
            init();
            for(int i=0;i<n&&!flag;i++)
                for(int j=0;j<n&&!flag;j++){
                    if(i==j)continue;
                    int t=(b[i][j]>>k)&1;
                    int aa=i+1,bb=j+1;
                    if(i%2==1&&j%2==1){
                        // |
                        if(t){
                            AddEdge(aa<<1|1,bb<<1);
                            AddEdge(bb<<1|1,aa<<1);
                        }
                        else {
                            AddEdge(aa<<1,aa<<1|1);
                            AddEdge(bb<<1,bb<<1|1);
                        }
                    }
                    else if(i%2==0&&j%2==0){
                        // &
                        if(t){
                            AddEdge(aa<<1|1,aa<<1);
                            AddEdge(bb<<1|1,bb<<1);
                        }
                        else {
                            AddEdge(aa<<1,bb<<1|1);
                            AddEdge(bb<<1,aa<<1|1);
                        }
                    }
                    else {
                        //printf("here");
                        // ^
                        if(t){
                            AddEdge(aa<<1,bb<<1|1);AddEdge(bb<<1|1,aa<<1);
                            AddEdge(bb<<1,aa<<1|1);AddEdge(aa<<1|1,bb<<1);
                        }
                        else {
                            AddEdge(aa<<1,bb<<1);AddEdge(bb<<1,aa<<1);
                            AddEdge(aa<<1|1,bb<<1|1);AddEdge(bb<<1|1,aa<<1|1);
                        }
                    }
                }
            memset(dfn,0,sizeof(dfn));
            memset(bleg,0,sizeof(bleg));
            times=top=0;
            for(int i=1;i<=n;i++){
                if(!dfn[i<<1])tarjan(i<<1);
                if(!dfn[i<<1|1])tarjan(i<<1|1);
            }
            for(int i=1;i<=n;i++)
                if(bleg[i<<1]==bleg[i<<1|1])flag=1;
                //printf("%d:%d\n",k,flag);
            if(flag)break;
        }
        if(flag)puts("NO");
        else puts("YES");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值