poj 3678(2-sat入门)

我的第一道2-cat题
2-cat问题解答:http://wenku.baidu.com/view/31fd7200bed5b9f3f90f1ce2.html
http://hi.baidu.com/godforbidyy/blog/item/40efcc33e3bfc409eac4af4f.html
转:(2-cat解题技巧)
1.构图(重点+难点)
2.求图的极大强连通子图 (模板)
3.把每个子图收缩成单个节点,根据原图关系构造一个有向无环图 (模板)
4.判断是否有解,无解则输出(退出) (这块常用到二分枚举答案,下面会详细讲解)
5.对新图进行拓扑排序 (模板)
6.自底向上进行选择、删除 (模板)
7.输出(模板)

题意:
一些点,点的取值可以是0或者1,没有告诉你具体取值。
一些边,有权值,有运算方式(并,或,异或),要求和这条边相连的两个点经过边上的运算后的结果是边的权值。
问你有没有可能把每个点赋值满足所有边的要求。
解:
    每个点只有0,1两种值,并且和边对面的点有约束条件,所以可以转化为2-sat问题。i*2和2*i+1为第i个数。
  and 等于 1时,要求i和j必须为1,不能为0.
  因为是必须选择的,所以如果and ==1 那么,如果两个点都为0,则不可能,就把0连到1上面,在用个一个集合的时候。
  或的时候,要选0 必须把1连到0上面

  AND  b = 1       <==>  _a->a   _b->b
  AND  b = 0       <==>  _a->_b  _b->_a//注意
  OR  b = 1        <==>  _a->b   _b->a//因为OR的时候例如a or b时,当a==1时,b就不判了。
  OR  b = 0        <==>  a->_a   b->_b
  XOR b = 1        <==>  _a->b   a->_b   _b->a  b->_a
  XOR b = 0        <==>  a->b    _a->_b   b->a  _b->_a
自己的代码:
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<iostream>
#include<cstring>
using namespace std;
const int NN = 2089;
int dfn[NN];
int low[NN];
int tmp;
int cnt;
int fa[NN];
vector<int>mp[NN];
int n,m;
int vis[NN];
stack<int>mystack;
void init()
{
    for(int i=0;i<n*2+5;i++)
    mp[i].clear();
    tmp=0;
    cnt=0;
}


void tarjan(int u)//求强连通
{
    vis[u]=1;
    dfn[u]=low[u]=tmp++;
    mystack.push(u);
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[v],low[u]);
        }
        else if(vis[v])
        low[u]=min(dfn[v],low[u]);
    }
    if(dfn[u]==low[u])
    {
      cnt++;
      int t;
      do
      {
        t=mystack.top();
        mystack.pop();
        vis[t]=0;
        fa[t]=cnt;
      }while(t!=u);
    }
}


int main()
{
    int a,b,c;
    string str;
    scanf("%d%d",&n,&m);
    init();
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        cin>>str;
        if(str=="AND")
        {
          if(c==1)
          {
           mp[2*a+1].push_back(2*a);
           mp[2*b+1].push_back(2*b);
          }
          else if(c==0)
          {
            mp[2*a].push_back(2*b+1);
            mp[2*b].push_back(2*a+1);
          }
        }
        if(str=="OR")
        {
          if(c==1)
          {
            mp[2*a+1].push_back(2*b);
            mp[2*b+1].push_back(2*a);
          }
          else
          {
            mp[2*a].push_back(2*a+1);
            mp[2*b].push_back(2*b+1);
          }
        }
        if(str=="XOR")
        {
            if(c==1)
            {
              mp[2*a].push_back(2*b+1);
              mp[2*b].push_back(2*a+1);
              mp[2*a+1].push_back(2*b);
              mp[2*b+1].push_back(2*a);
            }
            else
            {
              mp[2*a+1].push_back(2*b+1);
              mp[2*b+1].push_back(2*a+1);
              mp[2*a].push_back(2*b);
              mp[2*b].push_back(2*a);
            }
        }
    }
    for(int i=0;i<n*2;i++)
    {
        if(!dfn[i])
        tarjan(i);
    }
    int flag=1;
    for(int i=0;i<n;i++)
    {
        if(fa[i*2]==fa[i*2+1])//i*2和i*2+1不能在同一连通分量
        {flag=0;break;}
    }
    if(flag)
     cout<<"YES"<<endl;
     else
     cout<<"NO"<<endl;
 return 0;
}


你可能感兴趣的:(poj 3678(2-sat入门))