zoukankan      html  css  js  c++  java
  • POJ 3678 Katu Puzzle(2-SAT)

    【题目链接】 http://poj.org/problem?id=3678

    【题目大意】

      有一些变量,现在给出一些他们做AND,OR,或者XOR的结果(1或0),
      问这些变量是否存在满足所有结果的解集

    【题解】

      每个变量只有两种取值,0和1,所以我们拆点做2-SAT,
      i表示xi取0,i+N表示xi取1
      我们发现对于AND起来等于0的情况,两个变量至少有一个要是0,
      那么就有一个变量为1那么另一个变量必须为1的条件,
      对于AND起来等于1的情况我们发现两个变量必须取1,
      所以要否决取0的情况,我们连边i->i+N,这样我们发现变量i如果被选中,那么一定是无解的,
      这样就可以排除xi取0的情况。
      OR的两种情况和AND恰好相反,处理方式一致。
      对于XOR,如果结果为0,那么表示两个变量是状态相同,那么我们正反点之间均连双向边
      如果结果为1,那么我们将两个变量相反状态之间连双向边。
      最后求SCC判定连接情况即可。

    【代码】

    #include <cstdio>
    #include <algorithm>
    #include <vector>
    #include <cstring> 
    using namespace std;
    const int MAX_V=10000;
    int V; //顶点数
    vector<int> G[MAX_V]; //图的邻接表表示
    vector<int> rG[MAX_V]; //反向图
    vector<int> vs; //后序遍历
    bool used[MAX_V];
    int cmp[MAX_V]; //所属强连通分量的拓扑序
    void add_edge(int from,int to){
        G[from].push_back(to);
        rG[to].push_back(from);
    } 
    void dfs(int v){
        used[v]=1;
        for(int i=0;i<G[v].size();i++){
            if(!used[G[v][i]])dfs(G[v][i]);
        }vs.push_back(v);
    }
    void rdfs(int v,int k){
        used[v]=1;
        cmp[v]=k;
        for(int i=0;i<rG[v].size();i++){
            if(!used[rG[v][i]])rdfs(rG[v][i],k);
        }
    }
    int scc(){
        memset(used,0,sizeof(used));
        vs.clear();
        for(int v=0;v<V;v++){if(!used[v])dfs(v);}
        memset(used,0,sizeof(used));
        int k=0;
        for(int i=vs.size()-1;i>=0;i--){
            if(!used[vs[i]])rdfs(vs[i],k++);
        }return k;
    }
    int N,M;
    int x,y,c;
    char op[10];
    int solve(){
        V=N*2;
        // 0~N-1 表示 x取0
        // N~N+N-1 表示 x取1
        for(int i=0;i<M;i++){
            scanf("%d%d%d%s",&x,&y,&c,op);
            if(op[0]=='A'){
                if(c==0){
                    add_edge(y+N,x);
                    add_edge(x+N,y);
                }else{
                    add_edge(x,x+N);
                    add_edge(y,y+N);
                }
            }else if(op[0]=='O'){
                if(c==0){
                    add_edge(x+N,x);
                    add_edge(y+N,y);
                }else{
                    add_edge(x,y+N);
                    add_edge(y,x+N);
                }
            }else if(op[0]=='X'){
                if(c==0){
                    add_edge(x,y);
                    add_edge(y,x);
                    add_edge(x+N,y+N);
                    add_edge(y+N,x+N);
                }else{
                    add_edge(x,y+N);
                    add_edge(y,x+N);
                    add_edge(x+N,y);
                    add_edge(y+N,x);
                }
            }
        }int n=scc();
        int flag=1;
        for(int i=0;i<N;i++)if(cmp[i]==cmp[i+N])flag=0;
        puts(flag?"YES":"NO");
    }
    int main(){
        while(~scanf("%d%d",&N,&M)){
            solve();
        }return 0;
    }
  • 相关阅读:
    Date日期对象
    JAVA适配器
    java 对象的多态性
    简单轮播
    ecshop 教程地址
    瀑布流js排列
    phpcms 搜索结果页面栏目不显示解决 方法
    手机自动跳转
    字串符转换数字、取小数点后两位数的方法
    js 判断鼠标进去方向
  • 原文地址:https://www.cnblogs.com/forever97/p/poj3678.html
Copyright © 2011-2022 走看看