• 【Algorithm】2Sat模型


    一、关于模型:

    一个2-SAT模型应该是一个满足以下的条件的满足性问题:

    1、该模型中存在2n个可以分成n组的元素,每组两个元素

    2、每组元素中,选择了其中一个元素,另外一个元素就不能被选择。这两个元素记为a和!a

    3、该模型中的元素之间存在一些关系,且这些关系是对称的。(除非是同一组元素中的关系,这些关系限定了“必须选择”该组中的某一个元素,可能单独出现)

    满足上述条件,要求在满足给定关系的情况下在每组元素中选出一个元素的问题称为2-SAT问题。问是否存在即2-SAT判定问题,当然也可以求出一组可行解。

    当你看见一道题目,一些事物只有唯一且互斥的两种选择(比如两种取值,两种连接方式等等),那么可以分析下题目给出的条件是否满足对称性,若满足则可通过构图将题目转化成2-SAT问题了。

    二、关于构图

    要解2-SAT问题或者完成判定问题,首要的任务是构图。从《由对称性解2-SAT问题》这篇论文里,我们可以知道,构图的关键是找到冲突。

    若a和b冲突,即选a时不能选b,那么选a时必须选!b(因为不选b就必须选!b,这是一个2-SAT问题必须满足的条件),那么我们就连边<a,!b>。同样的道理,如果选了b,那么就不能选a,必须选!a,所以连边<b,!a>。这样的连边,显然是对称的。具体的例子可以看上面的论文。

    总之,弄清楚一点:如果存在边<a,b>,那么表示选择a时必须选择b。只要将所有这种“必须”关系都变成边,然后再判定2-sat或者求解2-sat,就能解决2-SAT问题了。

    三、关于解2-SAT

    方法是,对原图求一次强连通分量,然后看每组中的两个点是否属于同一个强连通分量,如果存在这种情况,那么无解

    然后对于缩点后的图G',我们将G'中所有边转置。进行拓扑排序。
    对于缩点后的所有点,我们先预处理求出所有冲突顶点。例如缩点后Ai所在强连通分支的ID
    为id[ Ai] ,同理~Ai在 id[ ~Ai ],所以冲突顶点conflict[ id[Ai] ]=conflict[ id[~Ai] ];同理conflict[ id[~Ai] ]=conflict[ id[Ai] ];

    设缩点后有Nscc个点。然后对拓扑序进行染色,初始化所有点color均为未着色,顺序遍历得到的拓扑序列,对于未着色的点x,将x染成红色,同时将所有与x矛盾的点conflic[x]染成蓝色。

    2-sat的一组解就等价于所有缩点后点颜色为红色的点,也就是color[ id[i] ]=RED的所有点。

    四、例题

    【Poj3207】【Ikki's Story IV - Panda's Trick】

    Description

    liympanda, one of Ikki’s friend, likes playing games with Ikki. Today after minesweeping with Ikki and winning so many times, he is tired of such easy games and wants to play another game with Ikki.

    liympanda has a magic circle and he puts it on a plane, there are n points on its boundary in circular border: 0, 1, 2, …, n − 1. Evil panda claims that he is connecting m pairs of points. To connect two points, liympanda either places the link entirely inside the circle or entirely outside the circle. Now liympanda tells Ikki no two links touch inside/outside the circle, except on the boundary. He wants Ikki to figure out whether this is possible…

    Despaired at the minesweeping game just played, Ikki is totally at a loss, so he decides to write a program to help him.

    Input

    The input contains exactly one test case.

    In the test case there will be a line consisting of of two integers: n and m (n ≤ 1,000, m ≤ 500). The following m lines each contain two integers ai and bi, which denote the endpoints of the ith wire. Every point will have at most one link.

    Output

    Output a line, either “panda is telling the truth...” or “the evil panda is lying again”.

    Sample Input

    4 2
    0 1
    3 2

    Sample Output

    panda is telling the truth...
      【Solution】
            最基础的2-sat。对每条边的两种状态算一组,通过是否相交的矛盾来来连边。 
            最后进行判定即可。
       【Code】
      1: Program PandaTrick(input,output);
    
      2:   type point=^node;
    
      3:        node=record
    
      4:          data:longint;
    
      5:          next:point;
    
      6:   end;
    
      7:   var map:array[0..2000]of point;
    
      8:       dfn,low,que,loc,col:array[0..2000]of longint;
    
      9:       x,y:array[1..2000]of longint;
    
     10:       i,n,m,q,j,t,time,quesum,loctmp,color:longint;
    
     11:   Procedure insert(x,y:longint);
    
     12:     var p:point;
    
     13:     begin
    
     14:       new(p);p^.data:=y;p^.next:=map[x];map[x]:=p;
    
     15:       new(p);p^.data:=x;p^.next:=map[y];map[y]:=p;
    
     16:     end;
    
     17:   procedure tarjan(x:longint);
    
     18:     var now:point;j,y:longint;
    
     19:     function min(a,b:longint):longint;
    
     20:       begin if a<b then exit(a) else exit(b);end;
    
     21:     begin
    
     22:       inc(time);low[x]:=time;dfn[x]:=time;
    
     23:       inc(quesum);que[quesum]:=x;loc[x]:=quesum;
    
     24:       now:=map[x];
    
     25:       while now<>nil do
    
     26:         begin
    
     27:           y:=now^.data;
    
     28:           if dfn[y]=0 then
    
     29:             begin
    
     30:               tarjan(y);
    
     31:               low[x]:=min(low[x],low[y]);
    
     32:             end       else
    
     33:           if loc[y]<>0 then low[x]:=min(low[x],dfn[y]);
    
     34:           now:=now^.next;
    
     35:         end;
    
     36:       if low[x]=dfn[x] then
    
     37:         begin
    
     38:           inc(color);
    
     39:           loctmp:=loc[x];
    
     40:           for j:=loctmp to quesum do
    
     41:             begin
    
     42:               col[que[j]]:=color;
    
     43:               loc[que[j]]:=0;
    
     44:             end;
    
     45:           quesum:=loctmp-1;
    
     46:         end;
    
     47:     end;
    
     48:   procedure swap(var a,b:Longint);
    
     49:     var t:longint;begin t:=a;a:=b;b:=t;end;
    
     50:   Function ok:boolean;
    
     51:     begin
    
     52:       for i:=1 to m do
    
     53:         if col[i]=col[i+m] then exit(false);
    
     54:       exit(true);
    
     55:     end;
    
     56:   begin
    
     57:     while not eof do
    
     58:       begin
    
     59:         readln(n,m);
    
     60:         fillchar(loc,sizeof(loc),0);
    
     61:         fillchar(col,sizeof(col),0);
    
     62:         fillchar(map,sizeof(map),0);
    
     63:         fillchar(dfn,sizeof(dfn),0);
    
     64:         fillchar(low,sizeof(low),0);
    
     65:         fillchar(que,sizeof(que),0);
    
     66:         time:=0;quesum:=0;color:=0;
    
     67:         for i:=1 to m do
    
     68:           begin
    
     69:             readln(x[i],y[i]);
    
     70:             if x[i]>y[i] then swap(x[i],y[i]);
    
     71:           end;
    
     72:         for i:=1 to m do
    
     73:           for j:=i+1 to m do
    
     74:             begin
    
     75:               if((x[j]>x[i])and(x[j]<y[i])and(y[j]>y[i]))or((x[i]>x[j])and(x[i]<y[j])and(y[i]>y[j]))then
    
     76:                 begin
    
     77:                   insert(i+m,j);insert(i,j+m);
    
     78:                 end;
    
     79:            end;
    
     80:         for i:=1 to m*2 do
    
     81:           if dfn[i]=low[i] then
    
     82:             tarjan(i);
    
     83:         if ok then writeln('panda is telling the truth...') else writeln('the evil panda is lying again');
    
     84:       end;
    
     85:   end.
    
     86: 

    【Poj 3678】Katu Puzzle

    Description

    Katu Puzzle is presented as a directed graph G(V, E) with each edge e(a, b) labeled by a boolean operator op (one of AND, OR, XOR) and an integer c (0 ≤ c ≤ 1). One Katu is solvable if one can find each vertex Vi a value Xi (0 ≤ Xi ≤ 1) such that for each edge e(a, b) labeled by op and c, the following formula holds:

    Xa op Xb = c

    Given a Katu Puzzle, your task is to determine whether it is solvable.

    Input

    The first line contains two integers N (1 ≤ N ≤ 1000) and M,(0 ≤ M ≤ 1,000,000) indicating the number of vertices and edges.
    The following M lines contain three integers a (0 ≤ a < N), b(0 ≤ b < N), c and an operator op each, describing the edges.

    Output

    Output a line containing "YES" or "NO".

    Sample Input

    4 4
    0 1 1 AND
    1 2 1 OR
    3 2 0 AND
    3 0 0 XOR

    Sample Output

    YES

    Hint

    X0 = 1, X1 = 1, X2 = 0, X3 = 1.

    【Solution】

    每个点只有0,1两种值,并且和边对面的点有约束条件,所以可以转化为2-sat问题。

    令i表示点i去0,i + n表示点i取1。

    点i与点j and 等于0时。 i + n -> j, j + n -> i

    and 等于 1时,要求i和j必须为1,不能为0.

    不能为0的处理时:如果i取0,那么i就要取1.

    即:i -> i + n。

    这个题连边时候需要很多注意。

    【Code】

      1: Program Katu(input,output);
    
      2:   type point=^node;
    
      3:        node=record
    
      4:          data:longint;
    
      5:          next:point;
    
      6:   end;
    
      7:   var map:array[1..2000]of point;
    
      8:       dfn,low,que,loc,col:array[1..2000]of longint;
    
      9:       x,y,i,n,m,q,j,c,t,time,quesum,loctmp,color:longint;s:string;
    
     10:   procedure insert(x,y:longint);
    
     11:     var P:point;
    
     12:     begin
    
     13:       new(p);p^.data:=y;p^.next:=map[x];map[x]:=p;
    
     14:     end;
    
     15:   procedure tarjan(x:longint);
    
     16:     var now:point;j,y:longint;
    
     17:     function min(a,b:longint):longint;
    
     18:       begin if a<b then exit(a) else exit(b);end;
    
     19:     begin
    
     20:       inc(time);low[x]:=time;dfn[x]:=time;
    
     21:       inc(quesum);que[quesum]:=x;loc[x]:=quesum;
    
     22:       now:=map[x];
    
     23:       while now<>nil do
    
     24:         begin
    
     25:           y:=now^.data;
    
     26:           if dfn[y]=0 then
    
     27:             begin
    
     28:               tarjan(y);
    
     29:               low[x]:=min(low[x],low[y]);
    
     30:             end       else
    
     31:           if loc[y]<>0 then low[x]:=min(low[x],dfn[y]);
    
     32:           now:=now^.next;
    
     33:         end;
    
     34:       if low[x]=dfn[x] then
    
     35:         begin
    
     36:           inc(color);
    
     37:           loctmp:=loc[x];
    
     38:           for j:=loctmp to quesum do
    
     39:             begin
    
     40:               col[que[j]]:=color;
    
     41:               loc[que[j]]:=0;
    
     42:             end;
    
     43:           quesum:=loctmp-1;
    
     44:         end;
    
     45:     end;
    
     46:   Function Ok:boolean;
    
     47:     begin
    
     48:       for i:=1 to n do
    
     49:         if col[i]=col[i+n] then exit(false);
    
     50:       exit(true);
    
     51:     end;
    
     52:   begin
    
     53:     assign(input,'Katu.in');reset(input);
    
     54:     assign(output,'Katu.out');rewrite(output);
    
     55:     readln(n,m);
    
     56:     fillchar(map,sizeof(map),0);
    
     57:     for i:=1 to m do
    
     58:       begin
    
     59:         read(x);read(y);read(c);readln(s);
    
     60:         inc(x);inc(y);
    
     61:         if s=' XOR' then
    
     62:           if c=1 then
    
     63:             begin
    
     64:               insert(x,y+n);insert(y+n,x);
    
     65:               insert(x+n,y);insert(y,x+n);
    
     66:             end
    
     67:           else
    
     68:             begin
    
     69:               insert(x,y);insert(y,x);
    
     70:               insert(x+n,y+n);insert(y+n,x+n);
    
     71:             end;
    
     72:         if s=' AND' then
    
     73:           if c=1 then
    
     74:             begin
    
     75:               insert(x+n,y+n);insert(y+n,x+n);
    
     76:               insert(x,x+n);insert(y,y+n);
    
     77:             end
    
     78:           else
    
     79:             begin
    
     80:               insert(x+n,y);insert(y+n,x);
    
     81:             end;
    
     82:         if s=' OR' then
    
     83:           if c=0 then
    
     84:             begin
    
     85:               insert(x,y);insert(y,x);
    
     86:               insert(x+n,x);insert(y+n,y);
    
     87:             end
    
     88:           else
    
     89:             begin
    
     90:               insert(x,y+n);insert(y,x+n);
    
     91:             end;
    
     92:       end;
    
     93:     fillchar(loc,sizeof(loc),0);
    
     94:     fillchar(col,sizeof(col),0);
    
     95:     fillchar(dfn,sizeof(dfn),0);
    
     96:     fillchar(low,sizeof(low),0);
    
     97:     fillchar(que,sizeof(que),0);
    
     98:     quesum:=0;color:=0;time:=0;
    
     99:     for i:=1 to n*2 do
    
    100:       if dfn[i]=0 then tarjan(i);
    
    101:     if ok then writeln('YES') else writeln('NO');
    
    102:   end.
  • 相关阅读:
    线段树学习笔记
    树状数组学习笔记
    P1816 忠诚 ST表模版
    NOIP 2017 D1T2 时间复杂度
    Ubuntu镜像源
    字符串数据结构模板
    白书的一些奇怪模板
    高精度模板
    大整数类模板
    线段树模板1
  • 原文地址:https://www.cnblogs.com/Loongint/p/2215451.html
Copyright © 2020-2023  润新知