PKU 3678 Katu Puzzle(2-SAT)

来源:互联网 发布:mysql order by 编辑:程序博客网 时间:2024/06/07 06:27

这几天看了2-SAT有关的论文,也做了一些相关的题目,个人的一点体会。

所谓的2-SAT就是给出一对矛盾,既他们是不可能相处在一起的,比如有家庭A,B。A家庭有a0,a1两个人,B家庭有b0,b1两个人,现在要求每个家庭出席一个人组成一个集合,要是没有任何约束条件,我们可以有4种选择满足条件,即(a0,b0) (a0,b1),(a1,b0),(a1,b1)。但是我们要是给出一个约束条件 比如说a1与b1不能同时出席,即是相当于不能兼容的一队,有此,我们可供选择的就减少了,减少了虽然是(a1,b1)这种选择,但是事实上还在条件上隐性的隐藏了一种约束,就是说假如我选择了a1,在B种我是没有选择的余地了,即只能是b0。而选择了b0之后又会带出与之相关的连锁约束。可以这么说,a1和b0的命运是掌握在一起的,即任何一个被选中,另外一个也必定要选中。

我们可以在得到一组矛盾的时候,把命运连在一起的连一条变,通过求强连通分量判断是否有可行解。

 

 

另外附上这道题目的一个详解链接,想必看后对2-SAT有更好的认识

 

http://hi.baidu.com/fhnstephen/blog/item/7c889883900a53db9023d95d.html

 

 

顺便附上我的代码(用了吉林大的Tarjan)

 

 

#include<cmath>

#include <stdio.h>

#include <string.h>

#include <set>

#include <queue>

#include <vector>

#include <iostream>

using namespace std;

 

#define V 6010

 

 

 

int n,m;

 

/*==================================================*/ 

 | Tarjan 强连通分量  

 | INIT: vec[]为邻接表; stop, cnt, scnt置0; pre[]置-1; 

 | CALL: for(i=0; i<n; ++i) if(-1==pre[i]) tarjan(i, n); 

/*==================================================*/ 

vector<int> vec[V]; 

int id[V], pre[V], low[V], s[V], stop, cnt, scnt; 

void tarjan(int v, int n)             // vertex: 0 ~ n-1 

  int t, minc = low[v] = pre[v] = cnt++; 

 vector<int>::iterator pv; 

 s[stop++] = v; 

  for (pv = vec[v].begin(); pv != vec[v].end(); ++pv) {

   if(-1 == pre[*pv]) tarjan(*pv, n); 

   if(low[*pv] < minc) minc=low[*pv]; 

 } 

  if(minc < low[v]) { 

  low[v] = minc; return; 

 } 

    do { 

  id[t = s[--stop]] = scnt; low[t] = n; 

    } while(t != v); 

 ++scnt;                           // 强连通分量的个数 

 

void addedge(int s,int e)

{

   // g[s].push_back(e);

   // rg[e].push_back(s);

vec[s].push_back(e);

}

 

void Init()     //初始化构图

{

    int i,j,a,b,res;

memset(pre,-1,sizeof(pre));

stop=cnt=scnt=0;

char ch[5];

    for(i=0;i<n;++i)

    {

vec[i].clear();

        //g[i].clear();

        //rg[i].clear();

}

while(m --)

{

scanf("%d %d %d %s",&a,&b,&res,&ch);

a<<=1;b<<=1;

a++;b++;

if(ch[0]=='A')

{

if(res==1)

{

addedge(a-1,a);

addedge(b-1,b);

}

else

{

addedge(a,b-1);

addedge(b,a-1);

}

}

else if(ch[0]=='O')

{

if(res==1)

{

addedge(a-1,b);

addedge(b-1,a);

}

else

{

addedge(a,a-1);

addedge(b,b-1);

}

}

else

{

if(res==0)

{

addedge(a,b);

addedge(b,a);

addedge(a-1,b-1);

addedge(b-1,a-1);

}

else

{

addedge(a-1,b);

addedge(b,a-1);

addedge(a,b-1);

addedge(b-1,a);

}

}

 

}

}

 

bool Judge()

{

int i;

for(i=0; i<n; ++i)

if(-1==pre[i]) tarjan(i, n);

for(i=0;i<n;i+=2)

if(id[i]==id[i+1])

return false;

return true;

}

 

 

 

void Solve()

{

    int i,j;

    n=n+n; 

    Init();

if(Judge()==false)

printf("NO/n");

else 

printf("YES/n");

}

 

int main()

{

    while(scanf("%d %d",&n,&m)!=EOF)

        Solve();

    return 0;

}

 

原创粉丝点击