poj3678-Katu Puzzle

\(n\)个bool变量和\(m\)条限制,每条限制为a op b=c的形式,其中op为逻辑运算,问是否存在合法解。

分析

这一类问题叫做2-SAT问题,有很多个两种取值的变量,其中有一些限制条件。2-SAT问题我们采用建模的方式,如果\(a\)选就一定要选\(b\),那么连有向边\((a,b)\)。2-SAT问题有解的条件就是\(a\)\(!a\)不在同一个强连通分量中,也就是说不产生矛盾。

几个基本逻辑运算的连边如下,其他的都可以转化为这几种:

  • a=true,\(!a\to a\)
  • a=false,\(a\to !a\)
  • a or b=true,\(!a\to b,!b\to a\)
  • a or b=false,等价于\(a=false,b=false\)
  • a and b=true,等价于\(a=true,b=true\)
  • a and b=false,\(a\to !b,b\to !a\)
  • a xor b=true,\(a\to !b,!a\to b,b\to !a,!b\to a\)
  • a xor b=false,\(a\to b,!a\to !b,b\to a,!b\to !a\)
  • a=b,等价于a xor b=false
  • \(a\ne b\),等价于a xor b=true

这道题就这样做完啦。

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=2e3+10;
const int maxm=4e6+10;
int dfn[maxn],low[maxn],dft=0,id[maxn],sta[maxn],top=0,col=0;
bool ins[maxn];
struct edge {
    int v,nxt;
};
struct graph {
    edge e[maxm];
    int h[maxn],tot;
    graph ():tot(0) {}
    void add(int u,int v) {
        e[++tot]=(edge){v,h[u]};
        h[u]=tot;
    }
    void Tarjan(int x) {
        dfn[x]=low[x]=++dft;
        sta[++top]=x;
        ins[x]=true;
        for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!dfn[v]) {
            Tarjan(v);
            low[x]=min(low[x],low[v]);
        } else if (ins[v]) low[x]=min(low[x],dfn[v]);
        if (low[x]==dfn[x]) {
            ++col;
            do id[sta[top--]]=col; while (sta[top+1]!=x);
        }
        ins[x]=false;
    }
    bool run(int n) {
        for (int i=1;i<=n;++i) if (id[i]==id[n+i]) return false;
        return true;
    }
} A;
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    int n=read(),m=read();
    for (int i=1;i<=m;++i) {
        int x=read()+1,y=read()+1,z=read();
        static char op[8];
        scanf("%s",op);
        if (op[0]=='A' && z) A.add(x+n,x),A.add(y+n,y); else
        if (op[0]=='A' && !z) A.add(x,y+n),A.add(y,x+n); else
        if (op[0]=='O' && z) A.add(x+n,y),A.add(y+n,x); else
        if (op[0]=='O' && !z) A.add(x,x+n),A.add(y,y+n); else 
        if (op[0]=='X' && z) A.add(x,y+n),A.add(x+n,y),A.add(y,x+n),A.add(y+n,x); else 
        if (op[0]=='X' && !z) A.add(x,y),A.add(x+n,y+n),A.add(y,x),A.add(y+n,x+n);
    }
    for (int i=1;i<=(n<<1);++i) if (!id[i]) A.Tarjan(i);
    puts(A.run(n)?"YES":"NO");
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/6741731.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值